From 92bc9d8801d9391bbc25f43e8a4f6e1818d9dd12 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 13 Aug 2022 10:13:37 -0400 Subject: [PATCH 01/34] Update AGP/Gradle (cherry picked from commit 34ac39e7e5e4d8846a55b396ac02d0758f1c0561) # Conflicts: # .github/workflows/build_pull_request.yml # .github/workflows/build_push.yml --- .github/runner-files/ci-gradle.properties | 5 - gradle.properties | 2 +- gradle/androidx.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 60756 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 275 +++++++++++++--------- gradlew.bat | 14 +- 7 files changed, 176 insertions(+), 124 deletions(-) delete mode 100644 .github/runner-files/ci-gradle.properties diff --git a/.github/runner-files/ci-gradle.properties b/.github/runner-files/ci-gradle.properties deleted file mode 100644 index 3b340e957..000000000 --- a/.github/runner-files/ci-gradle.properties +++ /dev/null @@ -1,5 +0,0 @@ -org.gradle.daemon=false -org.gradle.jvmargs=-Xmx5120m -org.gradle.workers.max=2 - -kotlin.incremental=false \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 01e93dde6..e9eff53d0 100755 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx10248m -XX:MaxPermSize=256m # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -org.gradle.jvmargs=-Xmx4096m +org.gradle.jvmargs=-Xmx5120m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index d5ab4b6c4..867b9d2b4 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -agp_version = "7.1.3" +agp_version = "7.2.2" lifecycle_version = "2.5.0" [libraries] diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..249e5832f090a2944b7473328c07c9755baa3196 100755 GIT binary patch delta 21931 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 delta 20228 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 \(.*\)$'` - 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_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${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"' # 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 @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 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,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + 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. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,101 @@ location of your Java installation." 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 -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 - -# 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 - # 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\"" - fi - i=`expr $i + 1` - 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" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" 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, 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. -# 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" +# For Cygwin or MSYS, switch paths to Windows format before running java +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 + 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 + # 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 +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# 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 107acd32c..f127cfd49 100755 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +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! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +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 From 422721bb64c5f99594b87a1c775d4a4b93301f81 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 13 Aug 2022 12:37:02 -0400 Subject: [PATCH 02/34] Update chapter recognition and related tests Includes 3e07100dc2725cb2d42050571232dd5d485b4de5 Co-authored-by: Saud-97 (cherry picked from commit 4a71022a609711378df48b62725ee863353193c8) # Conflicts: # .github/workflows/build_pull_request.yml # .github/workflows/build_push.yml # app/src/test/java/eu/kanade/tachiyomi/CustomRobolectricGradleTestRunner.kt --- app/build.gradle.kts | 12 +- .../util/chapter/ChapterRecognition.kt | 4 +- .../CustomRobolectricGradleTestRunner.kt | 12 - .../test/java/eu/kanade/tachiyomi/TestApp.kt | 8 - .../tachiyomi/data/backup/BackupTest.kt | 377 ------------- .../tachiyomi/data/database/CategoryTest.kt | 109 ---- .../data/database/ChapterRecognitionTest.kt | 497 ------------------ .../data/library/LibraryUpdateServiceTest.kt | 136 ----- .../util/chapter/ChapterRecognitionTest.kt | 275 ++++++++++ gradle/libs.versions.toml | 9 +- 10 files changed, 286 insertions(+), 1153 deletions(-) delete mode 100755 app/src/test/java/eu/kanade/tachiyomi/CustomRobolectricGradleTestRunner.kt delete mode 100644 app/src/test/java/eu/kanade/tachiyomi/TestApp.kt delete mode 100644 app/src/test/java/eu/kanade/tachiyomi/data/backup/BackupTest.kt delete mode 100644 app/src/test/java/eu/kanade/tachiyomi/data/database/CategoryTest.kt delete mode 100644 app/src/test/java/eu/kanade/tachiyomi/data/database/ChapterRecognitionTest.kt delete mode 100644 app/src/test/java/eu/kanade/tachiyomi/data/library/LibraryUpdateServiceTest.kt create mode 100644 app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 57c911e33..679dc52df 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,4 @@ +import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { @@ -225,10 +226,6 @@ dependencies { // Tests testImplementation(libs.junit) - testImplementation(libs.assertj.core) - testImplementation(libs.mockito.core) - - testImplementation(libs.bundles.robolectric) // For detecting memory leaks; see https://square.github.io/leakcanary/ // debugImplementation(libs.leakcanary.android) @@ -258,6 +255,13 @@ dependencies { } tasks { + withType { + useJUnitPlatform() + testLogging { + events(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED) + } + } + // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers) withType { kotlinOptions.freeCompilerArgs += listOf( diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognition.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognition.kt index dd3444961..d979f5d5c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognition.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognition.kt @@ -46,8 +46,8 @@ object ChapterRecognition { // Get chapter title with lower case var name = chapter.name.lowercase() - // Remove comma's from chapter. - name = name.replace(',', '.') + // Remove comma's or hyphens. + name = name.replace(',', '.').replace('-', '.') // Remove unwanted white spaces. unwantedWhiteSpace.findAll(name).let { diff --git a/app/src/test/java/eu/kanade/tachiyomi/CustomRobolectricGradleTestRunner.kt b/app/src/test/java/eu/kanade/tachiyomi/CustomRobolectricGradleTestRunner.kt deleted file mode 100755 index 3b334be41..000000000 --- a/app/src/test/java/eu/kanade/tachiyomi/CustomRobolectricGradleTestRunner.kt +++ /dev/null @@ -1,12 +0,0 @@ -package eu.kanade.tachiyomi - -import org.robolectric.RobolectricTestRunner -import org.robolectric.annotation.Config -import org.robolectric.manifest.AndroidManifest - -class CustomRobolectricGradleTestRunner(klass: Class<*>) : RobolectricTestRunner(klass) { - - override fun getAppManifest(config: Config): AndroidManifest { - return super.getAppManifest(config).apply { packageName = "eu.kanade.tachiyomi" } - } -} diff --git a/app/src/test/java/eu/kanade/tachiyomi/TestApp.kt b/app/src/test/java/eu/kanade/tachiyomi/TestApp.kt deleted file mode 100644 index 35a74ceb2..000000000 --- a/app/src/test/java/eu/kanade/tachiyomi/TestApp.kt +++ /dev/null @@ -1,8 +0,0 @@ -package eu.kanade.tachiyomi - -open class TestApp : App() { - - override fun setupAcra() { - // Do nothing - } -} diff --git a/app/src/test/java/eu/kanade/tachiyomi/data/backup/BackupTest.kt b/app/src/test/java/eu/kanade/tachiyomi/data/backup/BackupTest.kt deleted file mode 100644 index 75fe1320c..000000000 --- a/app/src/test/java/eu/kanade/tachiyomi/data/backup/BackupTest.kt +++ /dev/null @@ -1,377 +0,0 @@ -package eu.kanade.tachiyomi.data.backup - -import android.app.Application -import android.content.Context -import android.os.Build -import eu.kanade.tachiyomi.BuildConfig -import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner -import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupManager -import eu.kanade.tachiyomi.data.backup.legacy.models.Backup -import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory -import eu.kanade.tachiyomi.data.database.DatabaseHelper -import eu.kanade.tachiyomi.data.database.models.Category -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.ChapterImpl -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.data.database.models.MangaImpl -import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.database.models.TrackImpl -import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.source.online.HttpSource -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType -import kotlinx.coroutines.runBlocking -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.buildJsonObject -import org.assertj.core.api.Assertions.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito.RETURNS_DEEP_STUBS -import org.mockito.Mockito.anyLong -import org.mockito.Mockito.mock -import org.mockito.Mockito.`when` -import org.robolectric.RuntimeEnvironment -import org.robolectric.annotation.Config -import rx.Observable -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.InjektModule -import uy.kohesive.injekt.api.InjektRegistrar -import uy.kohesive.injekt.api.addSingleton - -/** - * Test class for the [LegacyBackupManager]. - * Note that this does not include the backup create/restore services. - */ -@Config(constants = BuildConfig::class, sdk = [Build.VERSION_CODES.M]) -@RunWith(CustomRobolectricGradleTestRunner::class) -class BackupTest { - // Create root object - var root = Backup() - - // Create information object - var information = buildJsonObject {} - - lateinit var app: Application - lateinit var context: Context - lateinit var source: HttpSource - - lateinit var legacyBackupManager: LegacyBackupManager - - lateinit var db: DatabaseHelper - - @Before - fun setup() { - app = RuntimeEnvironment.application - context = app.applicationContext - legacyBackupManager = LegacyBackupManager(context, 2) - db = legacyBackupManager.databaseHelper - - // Mock the source manager - val module = object : InjektModule { - override fun InjektRegistrar.registerInjectables() { - addSingleton(mock(SourceManager::class.java, RETURNS_DEEP_STUBS)) - } - } - Injekt.importModule(module) - - source = mock(HttpSource::class.java) - `when`(legacyBackupManager.sourceManager.get(anyLong())).thenReturn(source) - } - - /** - * Test that checks if no crashes when no categories in library. - */ - @Test - fun testRestoreEmptyCategory() { - // Restore Json - legacyBackupManager.restoreCategories(root.categories ?: emptyList()) - - // Check if empty - val dbCats = db.getCategories().executeAsBlocking() - assertThat(dbCats).isEmpty() - } - - /** - * Test to check if single category gets restored - */ - @Test - fun testRestoreSingleCategory() { - // Create category and add to json - val category = addSingleCategory("category") - - // Restore Json - legacyBackupManager.restoreCategories(root.categories ?: emptyList()) - - // Check if successful - val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking() - assertThat(dbCats).hasSize(1) - assertThat(dbCats[0].name).isEqualTo(category.name) - } - - /** - * Test to check if multiple categories get restored. - */ - @Test - fun testRestoreMultipleCategories() { - // Create category and add to json - val category = addSingleCategory("category") - val category2 = addSingleCategory("category2") - val category3 = addSingleCategory("category3") - val category4 = addSingleCategory("category4") - val category5 = addSingleCategory("category5") - - // Insert category to test if no duplicates on restore. - db.insertCategory(category).executeAsBlocking() - - // Restore Json - legacyBackupManager.restoreCategories(root.categories ?: emptyList()) - - // Check if successful - val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking() - assertThat(dbCats).hasSize(5) - assertThat(dbCats[0].name).isEqualTo(category.name) - assertThat(dbCats[1].name).isEqualTo(category2.name) - assertThat(dbCats[2].name).isEqualTo(category3.name) - assertThat(dbCats[3].name).isEqualTo(category4.name) - assertThat(dbCats[4].name).isEqualTo(category5.name) - } - - /** - * Test if restore of manga is successful - */ - @Test - fun testRestoreManga() { - // Add manga to database - val manga = getSingleManga("One Piece") - manga.readingModeType = ReadingModeType.VERTICAL.flagValue - manga.orientationType = OrientationType.PORTRAIT.flagValue - manga.id = db.insertManga(manga).executeAsBlocking().insertedId() - - var favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() - assertThat(favoriteManga).hasSize(1) - assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue) - assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue) - - // Change manga in database to default values - val dbManga = getSingleManga("One Piece") - dbManga.id = manga.id - db.insertManga(dbManga).executeAsBlocking() - - favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() - assertThat(favoriteManga).hasSize(1) - assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.DEFAULT.flagValue) - assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.DEFAULT.flagValue) - - // Restore local manga - legacyBackupManager.restoreMangaNoFetch(manga, dbManga) - - // Test if restore successful - favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() - assertThat(favoriteManga).hasSize(1) - assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue) - assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue) - - // Clear database to test manga fetch - clearDatabase() - - // Test if successful - favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() - assertThat(favoriteManga).hasSize(0) - - // Restore Json - // Create JSON from manga to test parser - val json = legacyBackupManager.parser.encodeToString(manga) - // Restore JSON from manga to test parser - val jsonManga = legacyBackupManager.parser.decodeFromString(json) - - // Restore manga with fetch observable - val networkManga = getSingleManga("One Piece") - networkManga.description = "This is a description" - `when`(source.fetchMangaDetails(jsonManga)).thenReturn(Observable.just(networkManga)) - - runBlocking { - legacyBackupManager.fetchManga(source, jsonManga) - - // Check if restore successful - val dbCats = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() - assertThat(dbCats).hasSize(1) - assertThat(dbCats[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue) - assertThat(dbCats[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue) - assertThat(dbCats[0].description).isEqualTo("This is a description") - } - } - - /** - * Test if chapter restore is successful - */ - @Test - fun testRestoreChapters() { - // Insert manga - val manga = getSingleManga("One Piece") - manga.id = legacyBackupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId() - - // Create restore list - val chapters = mutableListOf() - for (i in 1..8) { - val chapter = getSingleChapter("Chapter $i") - chapter.read = true - chapters.add(chapter) - } - - // Check parser - val chaptersJson = legacyBackupManager.parser.encodeToString(chapters) - val restoredChapters = legacyBackupManager.parser.decodeFromString>(chaptersJson) - - // Fetch chapters from upstream - // Create list - val chaptersRemote = mutableListOf() - (1..10).mapTo(chaptersRemote) { getSingleChapter("Chapter $it") } - `when`(source.fetchChapterList(manga)).thenReturn(Observable.just(chaptersRemote)) - - runBlocking { - legacyBackupManager.restoreChapters(source, manga, restoredChapters) - - val dbCats = legacyBackupManager.databaseHelper.getChapters(manga).executeAsBlocking() - assertThat(dbCats).hasSize(10) - assertThat(dbCats[0].read).isEqualTo(true) - } - } - - /** - * Test to check if history restore works - */ - @Test - fun restoreHistoryForManga() { - val manga = getSingleManga("One Piece") - manga.id = legacyBackupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId() - - // Create chapter - val chapter = getSingleChapter("Chapter 1") - chapter.manga_id = manga.id - chapter.read = true - chapter.id = legacyBackupManager.databaseHelper.insertChapter(chapter).executeAsBlocking().insertedId() - - val historyJson = getSingleHistory(chapter) - - val historyList = mutableListOf() - historyList.add(historyJson) - - // Check parser - val historyListJson = legacyBackupManager.parser.encodeToString(historyList) - val history = legacyBackupManager.parser.decodeFromString>(historyListJson) - - // Restore categories - legacyBackupManager.restoreHistoryForManga(history) - - val historyDB = legacyBackupManager.databaseHelper.getHistoryByMangaId(manga.id!!).executeAsBlocking() - assertThat(historyDB).hasSize(1) - assertThat(historyDB[0].last_read).isEqualTo(1000) - } - - /** - * Test to check if tracking restore works - */ - @Test - fun restoreTrackForManga() { - // Create mangas - val manga = getSingleManga("One Piece") - val manga2 = getSingleManga("Bleach") - manga.id = legacyBackupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId() - manga2.id = legacyBackupManager.databaseHelper.insertManga(manga2).executeAsBlocking().insertedId() - - // Create track and add it to database - // This tests duplicate errors. - val track = getSingleTrack(manga) - track.last_chapter_read = 5F - legacyBackupManager.databaseHelper.insertTrack(track).executeAsBlocking() - var trackDB = legacyBackupManager.databaseHelper.getTracks(manga).executeAsBlocking() - assertThat(trackDB).hasSize(1) - assertThat(trackDB[0].last_chapter_read).isEqualTo(5) - track.last_chapter_read = 7F - - // Create track for different manga to test track not in database - val track2 = getSingleTrack(manga2) - track2.last_chapter_read = 10F - - // Check parser and restore already in database - var trackList = listOf(track) - // Check parser - var trackListJson = legacyBackupManager.parser.encodeToString(trackList) - var trackListRestore = legacyBackupManager.parser.decodeFromString>(trackListJson) - legacyBackupManager.restoreTrackForManga(manga, trackListRestore) - - // Assert if restore works. - trackDB = legacyBackupManager.databaseHelper.getTracks(manga).executeAsBlocking() - assertThat(trackDB).hasSize(1) - assertThat(trackDB[0].last_chapter_read).isEqualTo(7) - - // Check parser and restore already in database with lower chapter_read - track.last_chapter_read = 5F - trackList = listOf(track) - legacyBackupManager.restoreTrackForManga(manga, trackList) - - // Assert if restore works. - trackDB = legacyBackupManager.databaseHelper.getTracks(manga).executeAsBlocking() - assertThat(trackDB).hasSize(1) - assertThat(trackDB[0].last_chapter_read).isEqualTo(7) - - // Check parser and restore, track not in database - trackList = listOf(track2) - - // Check parser - trackListJson = legacyBackupManager.parser.encodeToString(trackList) - trackListRestore = legacyBackupManager.parser.decodeFromString>(trackListJson) - legacyBackupManager.restoreTrackForManga(manga2, trackListRestore) - - // Assert if restore works. - trackDB = legacyBackupManager.databaseHelper.getTracks(manga2).executeAsBlocking() - assertThat(trackDB).hasSize(1) - assertThat(trackDB[0].last_chapter_read).isEqualTo(10) - } - - private fun clearJson() { - root = Backup() - information = buildJsonObject {} - } - - private fun addSingleCategory(name: String): Category { - val category = Category.create(name) - root.categories = listOf(category) - return category - } - - private fun clearDatabase() { - db.deleteMangas().executeAsBlocking() - db.deleteHistory().executeAsBlocking() - } - - private fun getSingleHistory(chapter: Chapter): DHistory { - return DHistory(chapter.url, 1000) - } - - private fun getSingleTrack(manga: Manga): TrackImpl { - val track = TrackImpl() - track.title = manga.title - track.manga_id = manga.id!! - track.sync_id = 1 - return track - } - - private fun getSingleManga(title: String): MangaImpl { - val manga = MangaImpl() - manga.source = 1 - manga.title = title - manga.url = "/manga/$title" - manga.favorite = true - return manga - } - - private fun getSingleChapter(name: String): ChapterImpl { - val chapter = ChapterImpl() - chapter.name = name - chapter.url = "/read-online/$name-page-1.html" - return chapter - } -} diff --git a/app/src/test/java/eu/kanade/tachiyomi/data/database/CategoryTest.kt b/app/src/test/java/eu/kanade/tachiyomi/data/database/CategoryTest.kt deleted file mode 100644 index c24baa1c6..000000000 --- a/app/src/test/java/eu/kanade/tachiyomi/data/database/CategoryTest.kt +++ /dev/null @@ -1,109 +0,0 @@ -package eu.kanade.tachiyomi.data.database - -import android.os.Build -import eu.kanade.tachiyomi.BuildConfig -import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner -import eu.kanade.tachiyomi.data.database.models.CategoryImpl -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.data.database.models.MangaCategory -import org.assertj.core.api.Assertions.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RuntimeEnvironment -import org.robolectric.annotation.Config - -@Config(constants = BuildConfig::class, sdk = [Build.VERSION_CODES.M]) -@RunWith(CustomRobolectricGradleTestRunner::class) -class CategoryTest { - - lateinit var db: DatabaseHelper - - @Before - fun setup() { - val app = RuntimeEnvironment.application - db = DatabaseHelper(app) - - // Create 5 manga - createManga("a") - createManga("b") - createManga("c") - createManga("d") - createManga("e") - } - - @Test - fun testHasCategories() { - // Create 2 categories - createCategory("Reading") - createCategory("Hold") - - val categories = db.getCategories().executeAsBlocking() - assertThat(categories).hasSize(2) - } - - @Test - fun testHasLibraryMangas() { - val mangas = db.getLibraryMangas().executeAsBlocking() - assertThat(mangas).hasSize(5) - } - - @Test - fun testHasCorrectFavorites() { - val m = Manga.create(0) - m.title = "title" - m.author = "" - m.artist = "" - m.thumbnail_url = "" - m.genre = "a list of genres" - m.description = "long description" - m.url = "url to manga" - m.favorite = false - db.insertManga(m).executeAsBlocking() - val mangas = db.getLibraryMangas().executeAsBlocking() - assertThat(mangas).hasSize(5) - } - - @Test - fun testMangaInCategory() { - // Create 2 categories - createCategory("Reading") - createCategory("Hold") - - // It should not have 0 as id - val c = db.getCategories().executeAsBlocking()[0] - assertThat(c.id).isNotZero - - // Add a manga to a category - val m = db.getLibraryMangas().executeAsBlocking()[0] - val mc = MangaCategory.create(m, c) - db.insertMangaCategory(mc).executeAsBlocking() - - // Get mangas from library and assert manga category is the same - val mangas = db.getLibraryMangas().executeAsBlocking() - for (manga in mangas) { - if (manga.id == m.id) { - assertThat(manga.category).isEqualTo(c.id) - } - } - } - - private fun createManga(title: String) { - val m = Manga.create(0) - m.title = title - m.author = "" - m.artist = "" - m.thumbnail_url = "" - m.genre = "a list of genres" - m.description = "long description" - m.url = "url to manga" - m.favorite = true - db.insertManga(m).executeAsBlocking() - } - - private fun createCategory(name: String) { - val c = CategoryImpl() - c.name = name - db.insertCategory(c).executeAsBlocking() - } -} diff --git a/app/src/test/java/eu/kanade/tachiyomi/data/database/ChapterRecognitionTest.kt b/app/src/test/java/eu/kanade/tachiyomi/data/database/ChapterRecognitionTest.kt deleted file mode 100644 index 33a0f2d17..000000000 --- a/app/src/test/java/eu/kanade/tachiyomi/data/database/ChapterRecognitionTest.kt +++ /dev/null @@ -1,497 +0,0 @@ -package eu.kanade.tachiyomi.data.database - -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.util.chapter.ChapterRecognition -import org.assertj.core.api.Assertions.assertThat -import org.junit.Before -import org.junit.Test - -class ChapterRecognitionTest { - /** - * The manga containing manga title - */ - lateinit var manga: Manga - - /** - * The chapter containing chapter name - */ - lateinit var chapter: Chapter - - /** - * Set chapter title - * @param name name of chapter - * @return chapter object - */ - private fun createChapter(name: String): Chapter { - chapter = Chapter.create() - chapter.name = name - return chapter - } - - /** - * Set manga title - * @param title title of manga - * @return manga object - */ - private fun createManga(title: String): Manga { - manga.title = title - return manga - } - - /** - * Called before test - */ - @Before - fun setup() { - manga = Manga.create(0).apply { title = "random" } - chapter = Chapter.create() - } - - /** - * Ch.xx base case - */ - @Test - fun ChCaseBase() { - createManga("Mokushiroku Alice") - - createChapter("Mokushiroku Alice Vol.1 Ch.4: Misrepresentation") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(4f) - } - - /** - * Ch. xx base case but space after period - */ - @Test - fun ChCaseBase2() { - createManga("Mokushiroku Alice") - - createChapter("Mokushiroku Alice Vol. 1 Ch. 4: Misrepresentation") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(4f) - } - - /** - * Ch.xx.x base case - */ - @Test - fun ChCaseDecimal() { - createManga("Mokushiroku Alice") - - createChapter("Mokushiroku Alice Vol.1 Ch.4.1: Misrepresentation") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(4.1f) - - createChapter("Mokushiroku Alice Vol.1 Ch.4.4: Misrepresentation") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(4.4f) - } - - /** - * Ch.xx.a base case - */ - @Test - fun ChCaseAlpha() { - createManga("Mokushiroku Alice") - - createChapter("Mokushiroku Alice Vol.1 Ch.4.a: Misrepresentation") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(4.1f) - - createChapter("Mokushiroku Alice Vol.1 Ch.4.b: Misrepresentation") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(4.2f) - - createChapter("Mokushiroku Alice Vol.1 Ch.4.extra: Misrepresentation") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(4.99f) - } - - /** - * Name containing one number base case - */ - @Test - fun OneNumberCaseBase() { - createManga("Bleach") - - createChapter("Bleach 567 Down With Snowwhite") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(567f) - } - - /** - * Name containing one number and decimal case - */ - @Test - fun OneNumberCaseDecimal() { - createManga("Bleach") - - createChapter("Bleach 567.1 Down With Snowwhite") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(567.1f) - - createChapter("Bleach 567.4 Down With Snowwhite") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(567.4f) - } - - /** - * Name containing one number and alpha case - */ - @Test - fun OneNumberCaseAlpha() { - createManga("Bleach") - - createChapter("Bleach 567.a Down With Snowwhite") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(567.1f) - - createChapter("Bleach 567.b Down With Snowwhite") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(567.2f) - - createChapter("Bleach 567.extra Down With Snowwhite") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(567.99f) - } - - /** - * Chapter containing manga title and number base case - */ - @Test - fun MangaTitleCaseBase() { - createManga("Solanin") - - createChapter("Solanin 028 Vol. 2") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28f) - } - - /** - * Chapter containing manga title and number decimal case - */ - @Test - fun MangaTitleCaseDecimal() { - createManga("Solanin") - - createChapter("Solanin 028.1 Vol. 2") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.1f) - - createChapter("Solanin 028.4 Vol. 2") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.4f) - } - - /** - * Chapter containing manga title and number alpha case - */ - @Test - fun MangaTitleCaseAlpha() { - createManga("Solanin") - - createChapter("Solanin 028.a Vol. 2") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.1f) - - createChapter("Solanin 028.b Vol. 2") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.2f) - - createChapter("Solanin 028.extra Vol. 2") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.99f) - } - - /** - * Extreme base case - */ - @Test - fun ExtremeCaseBase() { - createManga("Onepunch-Man") - - createChapter("Onepunch-Man Punch Ver002 028") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28f) - } - - /** - * Extreme base case decimal - */ - @Test - fun ExtremeCaseDecimal() { - createManga("Onepunch-Man") - - createChapter("Onepunch-Man Punch Ver002 028.1") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.1f) - - createChapter("Onepunch-Man Punch Ver002 028.4") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.4f) - } - - /** - * Extreme base case alpha - */ - @Test - fun ExtremeCaseAlpha() { - createManga("Onepunch-Man") - - createChapter("Onepunch-Man Punch Ver002 028.a") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.1f) - - createChapter("Onepunch-Man Punch Ver002 028.b") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.2f) - - createChapter("Onepunch-Man Punch Ver002 028.extra") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(28.99f) - } - - /** - * Chapter containing .v2 - */ - @Test - fun dotV2Case() { - createChapter("Vol.1 Ch.5v.2: Alones") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(5f) - } - - /** - * Check for case with number in manga title - */ - @Test - fun numberInMangaTitleCase() { - createManga("Ayame 14") - createChapter("Ayame 14 1 - The summer of 14") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(1f) - } - - /** - * Case with space between ch. x - */ - @Test - fun spaceAfterChapterCase() { - createManga("Mokushiroku Alice") - createChapter("Mokushiroku Alice Vol.1 Ch. 4: Misrepresentation") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(4f) - } - - /** - * Chapter containing mar(ch) - */ - @Test - fun marchInChapterCase() { - createManga("Ayame 14") - createChapter("Vol.1 Ch.1: March 25 (First Day Cohabiting)") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(1f) - } - - /** - * Chapter containing range - */ - @Test - fun rangeInChapterCase() { - createChapter("Ch.191-200 Read Online") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(191f) - } - - /** - * Chapter containing multiple zeros - */ - @Test - fun multipleZerosCase() { - createChapter("Vol.001 Ch.003: Kaguya Doesn't Know Much") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(3f) - } - - /** - * Chapter with version before number - */ - @Test - fun chapterBeforeNumberCase() { - createManga("Onepunch-Man") - createChapter("Onepunch-Man Punch Ver002 086 : Creeping Darkness [3]") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(86f) - } - - /** - * Case with version attached to chapter number - */ - @Test - fun vAttachedToChapterCase() { - createManga("Ansatsu Kyoushitsu") - createChapter("Ansatsu Kyoushitsu 011v002: Assembly Time") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(11f) - } - - /** - * Case where the chapter title contains the chapter - * But wait it's not actual the chapter number. - */ - @Test - fun NumberAfterMangaTitleWithChapterInChapterTitleCase() { - createChapter("Tokyo ESP 027: Part 002: Chapter 001") - createManga("Tokyo ESP") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(027f) - } - - /** - * unParsable chapter - */ - @Test - fun unParsableCase() { - createChapter("Foo") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(-1f) - } - - /** - * chapter with time in title - */ - @Test - fun timeChapterCase() { - createChapter("Fairy Tail 404: 00:00") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404f) - } - - /** - * chapter with alpha without dot - */ - @Test - fun alphaWithoutDotCase() { - createChapter("Asu No Yoichi 19a") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(19.1f) - } - - /** - * Chapter title containing extra and vol - */ - @Test - fun chapterContainingExtraCase() { - createManga("Fairy Tail") - - createChapter("Fairy Tail 404.extravol002") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404.99f) - - createChapter("Fairy Tail 404 extravol002") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404.99f) - - createChapter("Fairy Tail 404.evol002") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404.5f) - } - - /** - * Chapter title containing omake (japanese extra) and vol - */ - @Test - fun chapterContainingOmakeCase() { - createManga("Fairy Tail") - - createChapter("Fairy Tail 404.omakevol002") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404.98f) - - createChapter("Fairy Tail 404 omakevol002") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404.98f) - - createChapter("Fairy Tail 404.ovol002") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404.15f) - } - - /** - * Chapter title containing special and vol - */ - @Test - fun chapterContainingSpecialCase() { - createManga("Fairy Tail") - - createChapter("Fairy Tail 404.specialvol002") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404.97f) - - createChapter("Fairy Tail 404 specialvol002") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404.97f) - - createChapter("Fairy Tail 404.svol002") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(404.19f) - } - - /** - * Chapter title containing comma's - */ - @Test - fun chapterContainingCommasCase() { - createManga("One Piece") - - createChapter("One Piece 300,a") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(300.1f) - - createChapter("One Piece Ch,123,extra") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(123.99f) - - createChapter("One Piece the sunny, goes swimming 024,005") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(24.005f) - } - - /** - * Test for chapters containing season - */ - @Test - fun chapterContainingSeasonCase() { - createManga("D.I.C.E") - - createChapter("D.I.C.E[Season 001] Ep. 007") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(7f) - } - - /** - * Test for chapters in format sx - chapter xx - */ - @Test - fun chapterContainingSeasonCase2() { - createManga("The Gamer") - - createChapter("S3 - Chapter 20") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(20f) - } - - /** - * Test for chapters ending with s - */ - @Test - fun chaptersEndingWithS() { - createManga("One Outs") - - createChapter("One Outs 001") - ChapterRecognition.parseChapterNumber(chapter, manga) - assertThat(chapter.chapter_number).isEqualTo(1f) - } -} diff --git a/app/src/test/java/eu/kanade/tachiyomi/data/library/LibraryUpdateServiceTest.kt b/app/src/test/java/eu/kanade/tachiyomi/data/library/LibraryUpdateServiceTest.kt deleted file mode 100644 index bd96644c4..000000000 --- a/app/src/test/java/eu/kanade/tachiyomi/data/library/LibraryUpdateServiceTest.kt +++ /dev/null @@ -1,136 +0,0 @@ -package eu.kanade.tachiyomi.data.library - -import android.app.Application -import android.content.Context -import android.content.Intent -import android.os.Build -import eu.kanade.tachiyomi.BuildConfig -import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.LibraryManga -import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.source.online.HttpSource -import kotlinx.coroutines.runBlocking -import org.assertj.core.api.Assertions.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Matchers.anyLong -import org.mockito.Mockito.RETURNS_DEEP_STUBS -import org.mockito.Mockito.mock -import org.mockito.Mockito.`when` -import org.robolectric.Robolectric -import org.robolectric.RuntimeEnvironment -import org.robolectric.annotation.Config -import rx.Observable -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.InjektModule -import uy.kohesive.injekt.api.InjektRegistrar -import uy.kohesive.injekt.api.addSingleton - -@Config(constants = BuildConfig::class, sdk = [Build.VERSION_CODES.M]) -@RunWith(CustomRobolectricGradleTestRunner::class) -class LibraryUpdateServiceTest { - - lateinit var app: Application - lateinit var context: Context - lateinit var service: LibraryUpdateService - lateinit var source: HttpSource - - @Before - fun setup() { - app = RuntimeEnvironment.application - context = app.applicationContext - - // Mock the source manager - val module = object : InjektModule { - override fun InjektRegistrar.registerInjectables() { - addSingleton(mock(SourceManager::class.java, RETURNS_DEEP_STUBS)) - } - } - Injekt.importModule(module) - - service = Robolectric.setupService(LibraryUpdateService::class.java) - source = mock(HttpSource::class.java) - `when`(service.sourceManager.get(anyLong())).thenReturn(source) - } - - @Test - fun testLifecycle() { - // Smoke test - Robolectric.buildService(LibraryUpdateService::class.java) - .attach() - .create() - .startCommand(0, 0) - .destroy() - .get() - } - - @Test - fun testUpdateManga() { - val manga = createManga("/manga1")[0] - manga.id = 1L - service.db.insertManga(manga).executeAsBlocking() - - val sourceChapters = createChapters("/chapter1", "/chapter2") - - `when`(source.fetchChapterList(manga)).thenReturn(Observable.just(sourceChapters)) - - runBlocking { - service.updateManga(manga) - - assertThat(service.db.getChapters(manga).executeAsBlocking()).hasSize(2) - } - } - - @Test - fun testContinuesUpdatingWhenAMangaFails() { - var favManga = createManga("/manga1", "/manga2", "/manga3") - service.db.insertMangas(favManga).executeAsBlocking() - favManga = service.db.getLibraryMangas().executeAsBlocking() - - val chapters = createChapters("/chapter1", "/chapter2") - val chapters3 = createChapters("/achapter1", "/achapter2") - - // One of the updates will fail - `when`(source.fetchChapterList(favManga[0])).thenReturn(Observable.just(chapters)) - `when`(source.fetchChapterList(favManga[1])).thenReturn(Observable.error(Exception())) - `when`(source.fetchChapterList(favManga[2])).thenReturn(Observable.just(chapters3)) - - val intent = Intent() - val categoryId = intent.getIntExtra(LibraryUpdateService.KEY_CATEGORY, -1) - val target = LibraryUpdateService.Target.CHAPTERS - runBlocking { - service.addMangaToQueue(categoryId, target) - service.updateChapterList() - - // There are 3 network attempts and 2 insertions (1 request failed) - assertThat(service.db.getChapters(favManga[0]).executeAsBlocking()).hasSize(2) - assertThat(service.db.getChapters(favManga[1]).executeAsBlocking()).hasSize(0) - assertThat(service.db.getChapters(favManga[2]).executeAsBlocking()).hasSize(2) - } - } - - private fun createChapters(vararg urls: String): List { - val list = mutableListOf() - for (url in urls) { - val c = Chapter.create() - c.url = url - c.name = url.substring(1) - list.add(c) - } - return list - } - - private fun createManga(vararg urls: String): List { - val list = mutableListOf() - for (url in urls) { - val m = LibraryManga() - m.url = url - m.title = url.substring(1) - m.favorite = true - list.add(m) - } - return list - } -} diff --git a/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt b/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt new file mode 100644 index 000000000..1887ff4da --- /dev/null +++ b/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt @@ -0,0 +1,275 @@ +package eu.kanade.tachiyomi.util.chapter + +import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.Manga +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.parallel.Execution +import org.junit.jupiter.api.parallel.ExecutionMode + +@Execution(ExecutionMode.CONCURRENT) +class ChapterRecognitionTest { + + @Test + fun `Basic Ch prefix`() { + val mangaTitle = "Mokushiroku Alice" + + assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4: Misrepresentation", 4f) + } + + @Test + fun `Basic Ch prefix with space after period`() { + val mangaTitle = "Mokushiroku Alice" + + assertChapter(mangaTitle, "Mokushiroku Alice Vol. 1 Ch. 4: Misrepresentation", 4f) + } + + @Test + fun `Basic Ch prefix with decimal`() { + val mangaTitle = "Mokushiroku Alice" + + assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.1: Misrepresentation", 4.1f) + assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.4: Misrepresentation", 4.4f) + } + + @Test + fun `Basic Ch prefix with alpha postfix`() { + val mangaTitle = "Mokushiroku Alice" + + assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.a: Misrepresentation", 4.1f) + assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.b: Misrepresentation", 4.2f) + assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.extra: Misrepresentation", 4.99f) + } + + @Test + fun `Name containing one number`() { + val mangaTitle = "Bleach" + + assertChapter(mangaTitle, "Bleach 567 Down With Snowwhite", 567f) + } + + @Test + fun `Name containing one number and decimal`() { + val mangaTitle = "Bleach" + + assertChapter(mangaTitle, "Bleach 567.1 Down With Snowwhite", 567.1f) + assertChapter(mangaTitle, "Bleach 567.4 Down With Snowwhite", 567.4f) + } + + @Test + fun `Name containing one number and alpha`() { + val mangaTitle = "Bleach" + + assertChapter(mangaTitle, "Bleach 567.a Down With Snowwhite", 567.1f) + assertChapter(mangaTitle, "Bleach 567.b Down With Snowwhite", 567.2f) + assertChapter(mangaTitle, "Bleach 567.extra Down With Snowwhite", 567.99f) + } + + @Test + fun `Chapter containing manga title and number`() { + val mangaTitle = "Solanin" + + assertChapter(mangaTitle, "Solanin 028 Vol. 2", 28f) + } + + @Test + fun `Chapter containing manga title and number decimal`() { + val mangaTitle = "Solanin" + + assertChapter(mangaTitle, "Solanin 028.1 Vol. 2", 28.1f) + assertChapter(mangaTitle, "Solanin 028.4 Vol. 2", 28.4f) + } + + @Test + fun `Chapter containing manga title and number alpha`() { + val mangaTitle = "Solanin" + + assertChapter(mangaTitle, "Solanin 028.a Vol. 2", 28.1f) + assertChapter(mangaTitle, "Solanin 028.b Vol. 2", 28.2f) + assertChapter(mangaTitle, "Solanin 028.extra Vol. 2", 28.99f) + } + + @Test + fun `Extreme case`() { + val mangaTitle = "Onepunch-Man" + + assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028", 28f) + } + + @Test + fun `Extreme case with decimal`() { + val mangaTitle = "Onepunch-Man" + + assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.1", 28.1f) + assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.4", 28.4f) + } + + @Test + fun `Extreme case with alpha`() { + val mangaTitle = "Onepunch-Man" + + assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.a", 28.1f) + assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.b", 28.2f) + assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.extra", 28.99f) + } + + @Test + fun `Chapter containing dot v2`() { + val mangaTitle = "random" + + assertChapter(mangaTitle, "Vol.1 Ch.5v.2: Alones", 5f) + } + + @Test + fun `Number in manga title`() { + val mangaTitle = "Ayame 14" + + assertChapter(mangaTitle, "Ayame 14 1 - The summer of 14", 1f) + } + + @Test + fun `Space between ch x`() { + val mangaTitle = "Mokushiroku Alice" + + assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch. 4: Misrepresentation", 4f) + } + + @Test + fun `Chapter title with ch substring`() { + val mangaTitle = "Ayame 14" + + assertChapter(mangaTitle, "Vol.1 Ch.1: March 25 (First Day Cohabiting)", 1f) + } + + @Test + fun `Chapter containing multiple zeros`() { + val mangaTitle = "random" + + assertChapter(mangaTitle, "Vol.001 Ch.003: Kaguya Doesn't Know Much", 3f) + } + + @Test + fun `Chapter with version before number`() { + val mangaTitle = "Onepunch-Man" + + assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 086 : Creeping Darkness [3]", 86f) + } + + @Test + fun `Version attached to chapter number`() { + val mangaTitle = "Ansatsu Kyoushitsu" + + assertChapter(mangaTitle, "Ansatsu Kyoushitsu 011v002: Assembly Time", 11f) + } + + /** + * Case where the chapter title contains the chapter + * But wait it's not actual the chapter number. + */ + @Test + fun `Number after manga title with chapter in chapter title case`() { + val mangaTitle = "Tokyo ESP" + + assertChapter(mangaTitle, "Tokyo ESP 027: Part 002: Chapter 001", 027f) + } + + @Test + fun `Unparseable chapter`() { + val mangaTitle = "random" + + assertChapter(mangaTitle, "Foo", -1f) + } + + @Test + fun `Chapter with time in title`() { + val mangaTitle = "random" + + assertChapter(mangaTitle, "Fairy Tail 404: 00:00", 404f) + } + + @Test + fun `Chapter with alpha without dot`() { + val mangaTitle = "random" + + assertChapter(mangaTitle, "Asu No Yoichi 19a", 19.1f) + } + + @Test + fun `Chapter title containing extra and vol`() { + val mangaTitle = "Fairy Tail" + + assertChapter(mangaTitle, "Fairy Tail 404.extravol002", 404.99f) + assertChapter(mangaTitle, "Fairy Tail 404 extravol002", 404.99f) + assertChapter(mangaTitle, "Fairy Tail 404.evol002", 404.5f) + } + + @Test + fun `Chapter title containing omake (japanese extra) and vol`() { + val mangaTitle = "Fairy Tail" + + assertChapter(mangaTitle, "Fairy Tail 404.omakevol002", 404.98f) + assertChapter(mangaTitle, "Fairy Tail 404 omakevol002", 404.98f) + assertChapter(mangaTitle, "Fairy Tail 404.ovol002", 404.15f) + } + + @Test + fun `Chapter title containing special and vol`() { + val mangaTitle = "Fairy Tail" + + assertChapter(mangaTitle, "Fairy Tail 404.specialvol002", 404.97f) + assertChapter(mangaTitle, "Fairy Tail 404 specialvol002", 404.97f) + assertChapter(mangaTitle, "Fairy Tail 404.svol002", 404.19f) + } + + @Test + fun `Chapter title containing commas`() { + val mangaTitle = "One Piece" + + assertChapter(mangaTitle, "One Piece 300,a", 300.1f) + assertChapter(mangaTitle, "One Piece Ch,123,extra", 123.99f) + assertChapter(mangaTitle, "One Piece the sunny, goes swimming 024,005", 24.005f) + } + + @Test + fun `Chapter title containing hyphens`() { + val mangaTitle = "Solo Leveling" + + assertChapter(mangaTitle, "ch 122-a", 122.1f) + assertChapter(mangaTitle, "Solo Leveling Ch.123-extra", 123.99f) + assertChapter(mangaTitle, "Solo Leveling, 024-005", 24.005f) + assertChapter(mangaTitle, "Ch.191-200 Read Online", 191.200f) + } + + @Test + fun `Chapters containing season`() { + assertChapter("D.I.C.E", "D.I.C.E[Season 001] Ep. 007", 7f) + } + + @Test + fun `Chapters in format sx - chapter xx`() { + assertChapter("The Gamer", "S3 - Chapter 20", 20f) + } + + @Test + fun `Chapters ending with s`() { + assertChapter("One Outs", "One Outs 001", 1f) + } + + private fun assertChapter(mangaTitle: String, name: String, expected: Float) { + val chapter = createChapter(name) + ChapterRecognition.parseChapterNumber(chapter, createManga(mangaTitle)) + assertEquals(expected, chapter.chapter_number) + } + + private fun createManga(title: String): Manga { + val manga = Manga.create(0) + manga.title = title + return manga + } + + private fun createChapter(name: String): Chapter { + val chapter = Chapter.create() + chapter.name = name + return chapter + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ac3459b93..417351534 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,6 @@ coil_version = "2.0.0-rc03" conductor_version = "3.1.5" flowbinding_version = "1.2.0" shizuku_version = "12.1.0" -robolectric_version = "3.1.4" [libraries] android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2" @@ -87,12 +86,7 @@ aboutlibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibr shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku_version" } shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku_version" } -junit = "junit:junit:4.13.2" -assertj-core = "org.assertj:assertj-core:3.16.1" -mockito-core = "org.mockito:mockito-core:1.10.19" - -robolectric-core = { module = "org.robolectric:robolectric", version.ref = "robolectric_version" } -robolectric-playservices = { module = "org.robolectric:shadows-play-services", version.ref = "robolectric_version" } +junit = "org.junit.jupiter:junit-jupiter:5.9.0" leakcanary-android = "com.squareup.leakcanary:leakcanary-android:2.7" @@ -106,7 +100,6 @@ coil = ["coil-core","coil-gif",] flowbinding = ["flowbinding-android","flowbinding-appcompat","flowbinding-recyclerview","flowbinding-swiperefreshlayout","flowbinding-viewpager"] conductor = ["conductor-core","conductor-viewpager","conductor-support-preference"] shizuku = ["shizuku-api","shizuku-provider"] -robolectric = ["robolectric-core","robolectric-playservices"] [plugins] kotlinter = { id = "org.jmailen.kotlinter", version = "3.10.0"} From c7ecb58c61193324bd09a98fd990c9b2778f053c Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 13 Aug 2022 12:37:13 -0400 Subject: [PATCH 03/34] Update .editorconfig (cherry picked from commit be33a57d43ac7803cbec168c69108c05653fc520) --- .editorconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index b0aa6f2c2..bbef1d752 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,4 +2,6 @@ indent_size=4 insert_final_newline=true ij_kotlin_allow_trailing_comma=true -ij_kotlin_allow_trailing_comma_on_call_site=true \ No newline at end of file +ij_kotlin_allow_trailing_comma_on_call_site=true +ij_kotlin_name_count_to_use_star_import = 2147483647 +ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 \ No newline at end of file From 2ecd2bce5137a109409429cc7ceaf9639f6d7435 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 13 Aug 2022 12:46:00 -0400 Subject: [PATCH 04/34] Bump dependencies + compile SDK to 33 + linting (cherry picked from commit 3966a917ee76f007e581cf5c94a48d29090ef2c6) # Conflicts: # app/build.gradle.kts # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt --- app/build.gradle.kts | 22 +++++----- app/src/main/AndroidManifest.xml | 3 +- .../data/updater/AppUpdateChecker.kt | 1 + .../util/ExtensionInstallReceiver.kt | 5 ++- .../controller/SearchableNucleusController.kt | 21 +++++----- .../source/browse/BrowseSourceController.kt | 1 + .../ui/download/DownloadHeaderHolder.kt | 3 +- .../tachiyomi/ui/library/LibraryController.kt | 4 +- .../ui/library/LibrarySettingsSheet.kt | 2 + .../kanade/tachiyomi/ui/main/MainActivity.kt | 2 +- .../ui/manga/chapter/ChaptersSettingsSheet.kt | 1 + .../ui/reader/model/ReaderChapter.kt | 6 +-- .../ui/reader/setting/ReaderSettingsSheet.kt | 35 ++++++++-------- .../ui/reader/viewer/ReaderPageImageView.kt | 3 +- .../ui/reader/viewer/webtoon/WebtoonFrame.kt | 8 ++-- .../ui/setting/SettingsMainController.kt | 4 +- .../search/SettingsSearchController.kt | 4 +- .../tachiyomi/ui/webview/WebViewActivity.kt | 4 +- .../widget/TachiyomiBottomNavigationView.kt | 13 +++--- .../widget/preference/ThemesPreference.kt | 13 +++--- .../widget/sheet/BottomSheetViewPager.kt | 11 ++--- buildSrc/src/main/kotlin/AndroidConfig.kt | 2 +- gradle/androidx.versions.toml | 6 +-- gradle/kotlinx.versions.toml | 13 +++--- gradle/libs.versions.toml | 40 ++++++++++--------- 25 files changed, 120 insertions(+), 107 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 679dc52df..c00dc01c6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -19,6 +19,7 @@ if (gradle.startParameter.taskRequests.toString().contains("Standard")) { shortcutHelper.setFilePath("./shortcuts.xml") android { + namespace = "eu.kanade.tachiyomi" compileSdk = AndroidConfig.compileSdk ndkVersion = AndroidConfig.ndk @@ -229,6 +230,7 @@ dependencies { // For detecting memory leaks; see https://square.github.io/leakcanary/ // debugImplementation(libs.leakcanary.android) + implementation(libs.leakcanary.plumber) // SY --> // Changelog @@ -265,20 +267,20 @@ tasks { // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers) withType { kotlinOptions.freeCompilerArgs += listOf( - "-Xopt-in=kotlin.Experimental", - "-Xopt-in=kotlin.RequiresOptIn", - "-Xopt-in=kotlin.ExperimentalStdlibApi", - "-Xopt-in=kotlinx.coroutines.FlowPreview", - "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", - "-Xopt-in=kotlinx.coroutines.InternalCoroutinesApi", - "-Xopt-in=kotlinx.serialization.ExperimentalSerializationApi", - "-Xopt-in=coil.annotation.ExperimentalCoilApi", - "-Xopt-in=kotlin.time.ExperimentalTime", + "-opt-in=kotlin.Experimental", + "-opt-in=kotlin.RequiresOptIn", + "-opt-in=kotlin.ExperimentalStdlibApi", + "-opt-in=kotlinx.coroutines.FlowPreview", + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", + "-opt-in=kotlinx.coroutines.InternalCoroutinesApi", + "-opt-in=kotlinx.serialization.ExperimentalSerializationApi", + "-opt-in=coil.annotation.ExperimentalCoilApi", + "-opt-in=kotlin.time.ExperimentalTime", ) } // Duplicating Hebrew string assets due to some locale code issues on different devices - val copyHebrewStrings = task("copyHebrewStrings", type = Copy::class) { + val copyHebrewStrings by registering(Copy::class) { from("./src/main/res/values-he") into("./src/main/res/values-iw") include("**/*") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 12fc96ff3..f85dfad8b 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt index 0450d8e16..58c320b25 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt @@ -48,6 +48,7 @@ class AppUpdateChecker { when (result) { is AppUpdateResult.NewUpdate -> AppUpdateNotifier(context).promptUpdate(result.release) is AppUpdateResult.NewUpdateFdroidInstallation -> AppUpdateNotifier(context).promptFdroidUpdate() + else -> {} } result diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt index cdef6e436..943e82845 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt @@ -52,6 +52,7 @@ internal class ExtensionInstallReceiver(private val listener: Listener) : when (val result = getExtensionFromIntent(context, intent)) { is LoadResult.Success -> listener.onExtensionInstalled(result.extension) is LoadResult.Untrusted -> listener.onExtensionUntrusted(result.extension) + else -> {} } } } @@ -60,8 +61,8 @@ internal class ExtensionInstallReceiver(private val listener: Listener) : when (val result = getExtensionFromIntent(context, intent)) { is LoadResult.Success -> listener.onExtensionUpdated(result.extension) // Not needed as a package can't be upgraded if the signature is different - is LoadResult.Untrusted -> { - } + is LoadResult.Untrusted -> {} + else -> {} } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/SearchableNucleusController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/SearchableNucleusController.kt index 15f677bbc..fa0321304 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/SearchableNucleusController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/SearchableNucleusController.kt @@ -59,16 +59,17 @@ abstract class SearchableNucleusController filter.state = 1 is Filter.CheckBox -> filter.state = true + else -> {} } filterList = presenter.sourceFilters break@filter diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHeaderHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHeaderHolder.kt index 59d604974..3362c99ed 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHeaderHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHeaderHolder.kt @@ -28,8 +28,7 @@ class DownloadHeaderHolder(view: View, adapter: FlexibleAdapter<*>) : Expandable override fun onItemReleased(position: Int) { super.onItemReleased(position) binding.container.isDragged = false - mAdapter as DownloadAdapter mAdapter.expandAll() - mAdapter.downloadItemListener.onItemReleased(position) + (mAdapter as DownloadAdapter).downloadItemListener.onItemReleased(position) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index a09cac8c2..fa93429f3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -442,7 +442,7 @@ class LibraryController( override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { createOptionsMenu(menu, inflater, R.menu.library, R.id.action_search) // Mutate the filter icon because it needs to be tinted and the resource is shared. - menu.findItem(R.id.action_filter).icon.mutate() + menu.findItem(R.id.action_filter).icon?.mutate() // SY --> menu.findItem(R.id.action_sync_favorites).isVisible = preferences.isHentaiEnabled().get() @@ -472,7 +472,7 @@ class LibraryController( // Tint icon if there's a filter active if (settingsSheet.filters.hasActiveFilters()) { val filterColor = activity!!.getResourceColor(R.attr.colorFilterActive) - filterItem.icon.setTint(filterColor) + filterItem.icon?.setTint(filterColor) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt index 9824a8077..4217532aa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt @@ -451,6 +451,7 @@ class LibrarySettingsSheet( unreadBadge -> preferences.unreadBadge().set((item.checked)) localBadge -> preferences.localBadge().set((item.checked)) languageBadge -> preferences.languageBadge().set((item.checked)) + else -> {} } adapter.notifyItemChanged(item) } @@ -498,6 +499,7 @@ class LibrarySettingsSheet( when (item) { showTabs -> preferences.categoryTabs().set(item.checked) showNumberOfItems -> preferences.categoryNumberOfItems().set(item.checked) + else -> {} } adapter.notifyItemChanged(item) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 80208ace2..5a3fec971 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -520,7 +520,7 @@ class MainActivity : BaseActivity() { // Binding sometimes isn't actually instantiated yet somehow nav?.setOnItemSelectedListener(null) - binding?.toolbar.setNavigationOnClickListener(null) + binding?.toolbar?.setNavigationOnClickListener(null) } override fun onBackPressed() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt index 149eecbec..4a1e330b3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt @@ -161,6 +161,7 @@ class ChaptersSettingsSheet( downloaded -> presenter.setDownloadedFilter(newState) unread -> presenter.setUnreadFilter(newState) bookmarked -> presenter.setBookmarkedFilter(newState) + else -> {} } initModels() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderChapter.kt index b475c6a4f..a332a96ec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderChapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderChapter.kt @@ -10,9 +10,9 @@ data class ReaderChapter(val chapter: Chapter) { var state: State = State.Wait set(value) { - field = value - stateRelay.call(value) - } + field = value + stateRelay.call(value) + } private val stateRelay by lazy { BehaviorRelay.create(state) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt index 4e22f8418..14386d3c5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderSettingsSheet.kt @@ -34,27 +34,28 @@ class ReaderSettingsSheet( behavior.halfExpandedRatio = 0.25f val filterTabIndex = getTabViews().indexOf(colorFilterSettings) - binding.tabs.addOnTabSelectedListener(object : SimpleTabSelectedListener() { - override fun onTabSelected(tab: TabLayout.Tab?) { - val isFilterTab = tab?.position == filterTabIndex + binding.tabs.addOnTabSelectedListener( + object : SimpleTabSelectedListener() { + override fun onTabSelected(tab: TabLayout.Tab?) { + val isFilterTab = tab?.position == filterTabIndex - // Remove dimmed backdrop so color filter changes can be previewed - backgroundDimAnimator.run { - if (isFilterTab) { - if (animatedFraction < 1f) { - start() + // Remove dimmed backdrop so color filter changes can be previewed + backgroundDimAnimator.run { + if (isFilterTab) { + if (animatedFraction < 1f) { + start() + } + } else if (animatedFraction > 0f) { + reverse() } - } else if (animatedFraction > 0f) { - reverse() + } + + // Hide toolbars + if (activity.menuVisible != !isFilterTab) { + activity.setMenuVisibility(!isFilterTab) } } - - // Hide toolbars - if (activity.menuVisible != !isFilterTab) { - activity.setMenuVisibility(!isFilterTab) - } - } - }, + }, ) if (showColorFilterSettings) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt index 7e97847da..68a096aa8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt @@ -249,6 +249,7 @@ open class ReaderPageImageView @JvmOverloads constructor( ZoomStartPosition.LEFT -> setScaleAndCenter(scale, PointF(0F, 0F)) ZoomStartPosition.RIGHT -> setScaleAndCenter(scale, PointF(sWidth.toFloat(), 0F)) ZoomStartPosition.CENTER -> setScaleAndCenter(scale, center.also { it?.y = 0F }) + else -> {} } } @@ -310,7 +311,7 @@ open class ReaderPageImageView @JvmOverloads constructor( return true } - override fun onSingleTapConfirmed(e: MotionEvent?): Boolean { + override fun onSingleTapConfirmed(e: MotionEvent): Boolean { this@ReaderPageImageView.onViewClicked() return super.onSingleTapConfirmed(e) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonFrame.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonFrame.kt index fe9c9e628..35bb5104d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonFrame.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonFrame.kt @@ -52,7 +52,7 @@ class WebtoonFrame(context: Context) : FrameLayout(context) { * Scale listener used to delegate events to the recycler view. */ inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() { - override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean { + override fun onScaleBegin(detector: ScaleGestureDetector): Boolean { recycler?.onScaleBegin() return true } @@ -71,13 +71,13 @@ class WebtoonFrame(context: Context) : FrameLayout(context) { * Fling listener used to delegate events to the recycler view. */ inner class FlingListener : GestureDetector.SimpleOnGestureListener() { - override fun onDown(e: MotionEvent?): Boolean { + override fun onDown(e: MotionEvent): Boolean { return true } override fun onFling( - e1: MotionEvent?, - e2: MotionEvent?, + e1: MotionEvent, + e2: MotionEvent, velocityX: Float, velocityY: Float, ): Boolean { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt index a7663a82e..d9e9412c9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMainController.kt @@ -121,13 +121,13 @@ class SettingsMainController : SettingsController() { searchItem.setOnActionExpandListener( object : MenuItem.OnActionExpandListener { - override fun onMenuItemActionExpand(item: MenuItem?): Boolean { + override fun onMenuItemActionExpand(item: MenuItem): Boolean { preferences.lastSearchQuerySearchSettings().set("") // reset saved search query router.pushController(SettingsSearchController().withFadeTransaction()) return true } - override fun onMenuItemActionCollapse(item: MenuItem?): Boolean { + override fun onMenuItemActionCollapse(item: MenuItem): Boolean { return true } }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchController.kt index 462042abc..7d1049032 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/search/SettingsSearchController.kt @@ -74,11 +74,11 @@ class SettingsSearchController : searchItem.setOnActionExpandListener( object : MenuItem.OnActionExpandListener { - override fun onMenuItemActionExpand(item: MenuItem?): Boolean { + override fun onMenuItemActionExpand(item: MenuItem): Boolean { return true } - override fun onMenuItemActionCollapse(item: MenuItem?): Boolean { + override fun onMenuItemActionCollapse(item: MenuItem): Boolean { router.popCurrentController() return false } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewActivity.kt index 794df9097..0ba84840a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewActivity.kt @@ -166,12 +166,12 @@ class WebViewActivity : BaseActivity() { menu.findItem(R.id.action_web_back).apply { isEnabled = binding.webview.canGoBack() - icon.setTint(if (binding.webview.canGoBack()) iconTintColor else translucentIconTintColor) + icon?.setTint(if (binding.webview.canGoBack()) iconTintColor else translucentIconTintColor) } menu.findItem(R.id.action_web_forward).apply { isEnabled = binding.webview.canGoForward() - icon.setTint(if (binding.webview.canGoForward()) iconTintColor else translucentIconTintColor) + icon?.setTint(if (binding.webview.canGoForward()) iconTintColor else translucentIconTintColor) } return super.onPrepareOptionsMenu(menu) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiBottomNavigationView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiBottomNavigationView.kt index 169dad27f..190fd72e4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiBottomNavigationView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiBottomNavigationView.kt @@ -115,12 +115,13 @@ class TachiyomiBottomNavigationView @JvmOverloads constructor( .setInterpolator(interpolator) .setDuration(duration) .applySystemAnimatorScale(context) - .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator?) { - currentAnimator = null - postInvalidate() - } - }, + .setListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + currentAnimator = null + postInvalidate() + } + }, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreference.kt index e8769990a..576859fe6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreference.kt @@ -37,12 +37,13 @@ class ThemesPreference @JvmOverloads constructor(context: Context, attrs: Attrib recycler?.adapter = adapter // Retain scroll position on activity recreate after changing theme - recycler?.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - super.onScrolled(recyclerView, dx, dy) - lastScrollPosition = recyclerView.computeHorizontalScrollOffset() - } - }, + recycler?.addOnScrollListener( + object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + lastScrollPosition = recyclerView.computeHorizontalScrollOffset() + } + }, ) lastScrollPosition?.let { scrollToOffset(it) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/sheet/BottomSheetViewPager.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/sheet/BottomSheetViewPager.kt index f72eb3112..91b710757 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/sheet/BottomSheetViewPager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/sheet/BottomSheetViewPager.kt @@ -45,11 +45,12 @@ class BottomSheetViewPager @JvmOverloads constructor( } init { - addOnPageChangeListener(object : SimpleOnPageChangeListener() { - override fun onPageSelected(position: Int) { - requestLayout() - } - }, + addOnPageChangeListener( + object : SimpleOnPageChangeListener() { + override fun onPageSelected(position: Int) { + requestLayout() + } + }, ) } } diff --git a/buildSrc/src/main/kotlin/AndroidConfig.kt b/buildSrc/src/main/kotlin/AndroidConfig.kt index ccf121dc2..f0cf6fc23 100644 --- a/buildSrc/src/main/kotlin/AndroidConfig.kt +++ b/buildSrc/src/main/kotlin/AndroidConfig.kt @@ -1,5 +1,5 @@ object AndroidConfig { - const val compileSdk = 32 + const val compileSdk = 33 const val minSdk = 23 const val targetSdk = 29 const val ndk = "22.1.7171670" diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 867b9d2b4..f9a7c210e 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,6 +1,6 @@ [versions] agp_version = "7.2.2" -lifecycle_version = "2.5.0" +lifecycle_version = "2.5.1" [libraries] annotation = "androidx.annotation:annotation:1.4.0" @@ -10,7 +10,7 @@ constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" coordinatorlayout = "androidx.coordinatorlayout:coordinatorlayout:1.2.0" corektx = "androidx.core:core-ktx:1.8.0" splashscreen = "androidx.core:core-splashscreen:1.0.0-alpha02" -recyclerview = "androidx.recyclerview:recyclerview:1.3.0-beta01" +recyclerview = "androidx.recyclerview:recyclerview:1.3.0-beta02" swiperefreshlayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01" viewpager = "androidx.viewpager:viewpager:1.1.0-alpha01" @@ -27,4 +27,4 @@ workmanager = ["work-runtime", "guava"] [plugins] application = { id = "com.android.application", version.ref = "agp_version" } -library = { id = "com.android.library", version.ref = "agp_version" } \ No newline at end of file +library = { id = "com.android.library", version.ref = "agp_version" } diff --git a/gradle/kotlinx.versions.toml b/gradle/kotlinx.versions.toml index 268e66b5f..8d3cce7c1 100644 --- a/gradle/kotlinx.versions.toml +++ b/gradle/kotlinx.versions.toml @@ -1,7 +1,7 @@ [versions] -kotlin_version = "1.6.20" -coroutines_version = "1.6.1" -serialization_version = "1.3.2" +kotlin_version = "1.7.10" +coroutines_version = "1.6.4" +serialization_version = "1.3.3" [libraries] reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" } @@ -12,12 +12,11 @@ coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-androi serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_version" } serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization_version" } -serialization-gradle = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin_version"} +serialization-gradle = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin_version" } [bundles] coroutines = ["coroutines-core", "coroutines-android"] -serialization = ["serialization-json","serialization-protobuf"] +serialization = ["serialization-json", "serialization-protobuf"] [plugins] - -android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin_version"} \ No newline at end of file +android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin_version" } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 417351534..0e1b8a7a2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,14 +2,15 @@ aboutlib_version = "8.9.4" okhttp_version = "4.10.0" nucleus_version = "3.0.0" -coil_version = "2.0.0-rc03" -conductor_version = "3.1.5" +coil_version = "2.1.0" +conductor_version = "3.1.7" flowbinding_version = "1.2.0" shizuku_version = "12.1.0" +leakcanary = "2.9.1" [libraries] android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2" -google-services-gradle = "com.google.gms:google-services:4.3.10" +google-services-gradle = "com.google.gms:google-services:4.3.13" tachiyomi-api = "org.tachiyomi:source-api:1.1" @@ -33,13 +34,13 @@ jsoup = "org.jsoup:jsoup:1.14.3" disklrucache = "com.jakewharton:disklrucache:2.0.2" unifile = "com.github.tachiyomiorg:unifile:17bec43" -junrar = "com.github.junrar:junrar:7.5.2" +junrar = "com.github.junrar:junrar:7.5.3" -sqlitektx = "androidx.sqlite:sqlite-ktx:2.3.0-alpha02" +sqlitektx = "androidx.sqlite:sqlite-ktx:2.3.0-alpha03" sqlite-android = "com.github.requery:sqlite-android:3.36.0" preferencektx = "androidx.preference:preference-ktx:1.2.0" -flowpreferences = "com.fredporciuncula:flow-preferences:1.7.0" +flowpreferences = "com.fredporciuncula:flow-preferences:1.8.0" nucleus-core = { module = "info.android15.nucleus:nucleus", version.ref = "nucleus_version" } nucleus-supportv7 = { module = "info.android15.nucleus:nucleus-support-v7", version.ref = "nucleus_version" } @@ -77,8 +78,8 @@ flowbinding-viewpager = { module = "io.github.reactivecircus.flowbinding:flowbin logcat = "com.squareup.logcat:logcat:0.1" -acra-http = "ch.acra:acra-http:5.9.5" -firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.0.0" +acra-http = "ch.acra:acra-http:5.9.6" +firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.1.0" aboutlibraries-core = { module = "com.mikepenz:aboutlibraries-core", version.ref = "aboutlib_version" } aboutlibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlib_version" } @@ -86,21 +87,22 @@ aboutlibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibr shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku_version" } shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku_version" } +leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" } +leakcanary-plumber = { module = "com.squareup.leakcanary:plumber-android", version.ref = "leakcanary" } + junit = "org.junit.jupiter:junit-jupiter:5.9.0" -leakcanary-android = "com.squareup.leakcanary:leakcanary-android:2.7" - [bundles] -reactivex = ["rxandroid","rxjava","rxrelay"] -okhttp = ["okhttp-core","okhttp-logging","okhttp-dnsoverhttps"] +reactivex = ["rxandroid", "rxjava", "rxrelay"] +okhttp = ["okhttp-core", "okhttp-logging", "okhttp-dnsoverhttps"] js-engine = ["quickjs-android", "duktape-android"] sqlite = ["sqlitektx", "sqlite-android"] -nucleus = ["nucleus-core","nucleus-supportv7"] -coil = ["coil-core","coil-gif",] -flowbinding = ["flowbinding-android","flowbinding-appcompat","flowbinding-recyclerview","flowbinding-swiperefreshlayout","flowbinding-viewpager"] -conductor = ["conductor-core","conductor-viewpager","conductor-support-preference"] -shizuku = ["shizuku-api","shizuku-provider"] +nucleus = ["nucleus-core", "nucleus-supportv7"] +coil = ["coil-core", "coil-gif"] +flowbinding = ["flowbinding-android", "flowbinding-appcompat", "flowbinding-recyclerview", "flowbinding-swiperefreshlayout", "flowbinding-viewpager"] +conductor = ["conductor-core", "conductor-viewpager", "conductor-support-preference"] +shizuku = ["shizuku-api", "shizuku-provider"] [plugins] -kotlinter = { id = "org.jmailen.kotlinter", version = "3.10.0"} -versionsx = { id = "com.github.ben-manes.versions", version = "0.42.0"} \ No newline at end of file +kotlinter = { id = "org.jmailen.kotlinter", version = "3.11.1" } +versionsx = { id = "com.github.ben-manes.versions", version = "0.42.0" } \ No newline at end of file From 63cd8f8c07568b3800659ad7f6ad80e416184730 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 9 Jul 2022 00:00:18 -0400 Subject: [PATCH 05/34] Use Material3 switches in XML layouts (cherry picked from commit da7a64b40dda3368565b329e519da3283c797131) # Conflicts: # app/src/main/res/layout/reader_general_settings.xml # app/src/main/res/layout/reader_pager_settings.xml # app/src/main/res/layout/reader_webtoon_settings.xml (cherry picked from commit 72aba18dab4f21e8f2c569a1321bdccdf062039a) --- .../layout/edit_merged_settings_header.xml | 9 +-- .../main/res/layout/eh_dialog_categories.xml | 66 ++++++++++++------- .../res/layout/migration_bottom_sheet.xml | 24 +++---- .../layout/pref_widget_switch_material.xml | 2 +- app/src/main/res/layout/reader_activity.xml | 6 +- .../layout/reader_color_filter_settings.xml | 24 +++---- .../res/layout/reader_general_settings.xml | 60 ++++++++--------- .../main/res/layout/reader_pager_settings.xml | 42 ++++++------ .../res/layout/reader_webtoon_settings.xml | 36 +++++----- app/src/main/res/values/themes.xml | 2 + 10 files changed, 147 insertions(+), 124 deletions(-) diff --git a/app/src/main/res/layout/edit_merged_settings_header.xml b/app/src/main/res/layout/edit_merged_settings_header.xml index 17f3a9d16..d56adb660 100644 --- a/app/src/main/res/layout/edit_merged_settings_header.xml +++ b/app/src/main/res/layout/edit_merged_settings_header.xml @@ -9,8 +9,7 @@ - + android:layout_height="match_parent" + android:paddingVertical="16dp" + android:paddingHorizontal="16dp"/> diff --git a/app/src/main/res/layout/eh_dialog_categories.xml b/app/src/main/res/layout/eh_dialog_categories.xml index 222a3c9f8..f35a76e12 100644 --- a/app/src/main/res/layout/eh_dialog_categories.xml +++ b/app/src/main/res/layout/eh_dialog_categories.xml @@ -4,13 +4,13 @@ android:layout_height="wrap_content" android:layout_row="0" android:layout_column="0" + android:divider="?attr/colorOnBackground" android:padding="16dp" - android:showDividers="middle" - android:divider="?attr/colorOnBackground"> + android:showDividers="middle"> + android:layout_height="match_parent"> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> - + android:layout_gravity="center" + android:paddingHorizontal="16dp" + android:paddingVertical="16dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/migration_bottom_sheet.xml b/app/src/main/res/layout/migration_bottom_sheet.xml index 730f20887..29137d372 100644 --- a/app/src/main/res/layout/migration_bottom_sheet.xml +++ b/app/src/main/res/layout/migration_bottom_sheet.xml @@ -157,22 +157,22 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/sourceGroup_divider"> - - - - diff --git a/app/src/main/res/layout/pref_widget_switch_material.xml b/app/src/main/res/layout/pref_widget_switch_material.xml index 65bcaf6dc..53dea7ec0 100644 --- a/app/src/main/res/layout/pref_widget_switch_material.xml +++ b/app/src/main/res/layout/pref_widget_switch_material.xml @@ -1,5 +1,5 @@ - - diff --git a/app/src/main/res/layout/reader_color_filter_settings.xml b/app/src/main/res/layout/reader_color_filter_settings.xml index c9897115f..f851e8cad 100644 --- a/app/src/main/res/layout/reader_color_filter_settings.xml +++ b/app/src/main/res/layout/reader_color_filter_settings.xml @@ -11,12 +11,12 @@ - @@ -61,12 +61,12 @@ - - - diff --git a/app/src/main/res/layout/reader_general_settings.xml b/app/src/main/res/layout/reader_general_settings.xml index cb7cd47c5..bd9e25513 100644 --- a/app/src/main/res/layout/reader_general_settings.xml +++ b/app/src/main/res/layout/reader_general_settings.xml @@ -17,95 +17,95 @@ android:entries="@array/reader_themes" app:title="@string/pref_reader_theme" /> - - - - - - - - - - diff --git a/app/src/main/res/layout/reader_pager_settings.xml b/app/src/main/res/layout/reader_pager_settings.xml index 6472ae880..ea3e9949f 100644 --- a/app/src/main/res/layout/reader_pager_settings.xml +++ b/app/src/main/res/layout/reader_pager_settings.xml @@ -37,12 +37,12 @@ android:entries="@array/image_scale_type" app:title="@string/pref_image_scale_type" /> - @@ -60,59 +60,59 @@ android:entries="@array/page_layouts" app:title="@string/page_layout" /> - - - - - - diff --git a/app/src/main/res/layout/reader_webtoon_settings.xml b/app/src/main/res/layout/reader_webtoon_settings.xml index 78de47a46..fe1069bfd 100644 --- a/app/src/main/res/layout/reader_webtoon_settings.xml +++ b/app/src/main/res/layout/reader_webtoon_settings.xml @@ -37,48 +37,48 @@ android:entries="@array/webtoon_side_padding" app:title="@string/pref_webtoon_side_padding" /> - - - - - - diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 67867d06f..0c408c823 100755 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -77,6 +77,8 @@ @style/Widget.Tachiyomi.BottomNavigationView @style/Widget.Tachiyomi.NavigationRailView @style/Widget.Tachiyomi.Switch + @style/Widget.Material3.CompoundButton.MaterialSwitch + @style/Widget.Tachiyomi.Switch @style/Widget.Tachiyomi.Slider @style/Widget.Material3.CardView.Elevated From ae7a4744bd8217699bb17a957e78943a5904f773 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 13 Aug 2022 13:08:16 -0400 Subject: [PATCH 06/34] Configure SQLite - Turn on `foreign_keys` to cascade on delete properly - Turn on `journal_mode` and set `synchronous` to NORMAL which may help performance for larger libraries Based on d977b89af1f2a8850437ebd978535fc3fbfd257e Co-authored-by: ghostbear (cherry picked from commit ac4f98e152c66c388dd5f098725f4196df3a7339) --- .../eu/kanade/tachiyomi/data/database/DbOpenCallback.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt index 93826ab8a..5ed6b91f9 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt @@ -115,5 +115,14 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) { override fun onConfigure(db: SupportSQLiteDatabase) { db.setForeignKeyConstraintsEnabled(true) + setPragma(db, "foreign_keys = ON") + setPragma(db, "journal_mode = WAL") + setPragma(db, "synchronous = NORMAL") + } + + private fun setPragma(db: SupportSQLiteDatabase, pragma: String) { + val cursor = db.query("PRAGMA $pragma") + cursor.moveToFirst() + cursor.close() } } From a126180ca31043fb256e39c0c7af5a0a3bb9c79c Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 9 Jul 2022 17:51:58 -0400 Subject: [PATCH 07/34] Replace deprecated ACTION_MEDIA_SCANNER_SCAN_FILE intent (cherry picked from commit 0b4f3f553263281333c6475cdd1a9aea414ce877) (cherry picked from commit c7e44aa22f61e70afb278e00b3e751bf42ec9847) --- .../data/notification/NotificationReceiver.kt | 3 ++- .../eu/kanade/tachiyomi/data/saver/ImageSaver.kt | 3 ++- .../eu/kanade/tachiyomi/util/storage/DiskUtil.kt | 15 ++------------- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 26fc7dea7..2b1d0d0b0 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -7,6 +7,7 @@ import android.content.Intent import android.net.Uri import android.os.Build import androidx.core.content.ContextCompat +import androidx.core.net.toUri import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupRestoreService import eu.kanade.tachiyomi.data.database.DatabaseHelper @@ -193,7 +194,7 @@ class NotificationReceiver : BroadcastReceiver() { val file = File(path) file.delete() - DiskUtil.scanMedia(context, file) + DiskUtil.scanMedia(context, file.toUri()) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt index 673b93654..63604f1c0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt @@ -8,6 +8,7 @@ import android.net.Uri import android.os.Build import android.os.Environment import android.provider.MediaStore +import androidx.core.net.toUri import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.cacheImageDir @@ -82,7 +83,7 @@ class ImageSaver( } } - DiskUtil.scanMedia(context, destFile) + DiskUtil.scanMedia(context, destFile.toUri()) return destFile.getUriCompat(context) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt index 26fa1d93a..bcbbf2520 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt @@ -1,12 +1,11 @@ package eu.kanade.tachiyomi.util.storage import android.content.Context -import android.content.Intent +import android.media.MediaScannerConnection import android.net.Uri import android.os.Environment import android.os.StatFs import androidx.core.content.ContextCompat -import androidx.core.net.toUri import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.util.lang.Hash import java.io.File @@ -74,21 +73,11 @@ object DiskUtil { } } - /** - * Scans the given file so that it can be shown in gallery apps, for example. - */ - fun scanMedia(context: Context, file: File) { - scanMedia(context, file.toUri()) - } - /** * Scans the given file so that it can be shown in gallery apps, for example. */ fun scanMedia(context: Context, uri: Uri) { - val action = Intent.ACTION_MEDIA_SCANNER_SCAN_FILE - val mediaScanIntent = Intent(action) - mediaScanIntent.data = uri - context.sendBroadcast(mediaScanIntent) + MediaScannerConnection.scanFile(context, arrayOf(uri.path), null, null) } /** From 58ef23995964bd20867ac3b359b5d8f9ceb01aa8 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 14 Jul 2022 23:01:19 -0400 Subject: [PATCH 08/34] Make default user agent string configurable (cherry picked from commit 4ee1d72b6f8278d84da6f75d218a51261d175e18) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt (cherry picked from commit bcf93989877ecf0d09f4a3d28584c107aacf9393) --- .../data/preference/PreferenceKeys.kt | 2 ++ .../data/preference/PreferencesHelper.kt | 2 ++ .../kanade/tachiyomi/network/NetworkHelper.kt | 4 ++++ .../interceptor/CloudflareInterceptor.kt | 3 +-- .../interceptor/UserAgentInterceptor.kt | 8 +++++-- .../tachiyomi/source/online/HttpSource.kt | 6 +---- .../ui/setting/SettingsAdvancedController.kt | 22 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 8 files changed, 40 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 026df2b92..ba09ecb01 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -65,6 +65,8 @@ object PreferenceKeys { const val dohProvider = "doh_provider" + const val defaultUserAgent = "default_user_agent" + const val defaultChapterFilterByRead = "default_chapter_filter_by_read" const val defaultChapterFilterByDownloaded = "default_chapter_filter_by_downloaded" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 12a17c466..5276dbdff 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -308,6 +308,8 @@ class PreferencesHelper(val context: Context) { fun dohProvider() = prefs.getInt(Keys.dohProvider, -1) + fun defaultUserAgent() = flowPrefs.getString(Keys.defaultUserAgent, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.124 Safari/537.36 Edg/102.0.1245.44") + fun lastSearchQuerySearchSettings() = flowPrefs.getString("last_search_query", "") fun filterChapterByRead() = prefs.getInt(Keys.defaultChapterFilterByRead, Manga.SHOW_ALL) diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index 4056fce2e..a14525bbe 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -64,4 +64,8 @@ open /* SY <-- */ class NetworkHelper(context: Context) { .addInterceptor(CloudflareInterceptor(context)) .build() } + + val defaultUserAgent by lazy { + preferences.defaultUserAgent().get() + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt index b697a9f16..2e43e01b7 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt @@ -9,7 +9,6 @@ import android.widget.Toast import androidx.core.content.ContextCompat import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.network.NetworkHelper -import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.WebViewClientCompat @@ -109,7 +108,7 @@ class CloudflareInterceptor(private val context: Context) : Interceptor { // Avoid sending empty User-Agent, Chromium WebView will reset to default if empty webview.settings.userAgentString = request.header("User-Agent") - ?: HttpSource.DEFAULT_USER_AGENT + ?: networkHelper.defaultUserAgent webview.webViewClient = object : WebViewClientCompat() { override fun onPageFinished(view: WebView, url: String) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/interceptor/UserAgentInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/network/interceptor/UserAgentInterceptor.kt index 5a3789eec..e5d1c2656 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/interceptor/UserAgentInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/interceptor/UserAgentInterceptor.kt @@ -1,10 +1,14 @@ package eu.kanade.tachiyomi.network.interceptor -import eu.kanade.tachiyomi.source.online.HttpSource +import eu.kanade.tachiyomi.network.NetworkHelper import okhttp3.Interceptor import okhttp3.Response +import uy.kohesive.injekt.injectLazy class UserAgentInterceptor : Interceptor { + + private val networkHelper: NetworkHelper by injectLazy() + override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() @@ -12,7 +16,7 @@ class UserAgentInterceptor : Interceptor { val newRequest = originalRequest .newBuilder() .removeHeader("User-Agent") - .addHeader("User-Agent", HttpSource.DEFAULT_USER_AGENT) + .addHeader("User-Agent", networkHelper.defaultUserAgent) .build() chain.proceed(newRequest) } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt index f1235bb9c..acf05bac1 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt @@ -99,7 +99,7 @@ abstract class HttpSource : CatalogueSource { * Headers builder for requests. Implementations can override this method for custom headers. */ protected open fun headersBuilder() = Headers.Builder().apply { - add("User-Agent", DEFAULT_USER_AGENT) + add("User-Agent", network.defaultUserAgent) } /** @@ -417,8 +417,4 @@ abstract class HttpSource : CatalogueSource { this.delegate = delegate } // EXH <-- - - companion object { - const val DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.124 Safari/537.36 Edg/102.0.1245.44" - } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt index 9f7600200..7dd045b83 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt @@ -219,6 +219,28 @@ class SettingsAdvancedController : SettingsController() { true } } + editTextPreference { + key = Keys.defaultUserAgent + titleRes = R.string.pref_user_agent_string + text = preferences.defaultUserAgent().get() + summary = network.defaultUserAgent + + onChange { + activity?.toast(R.string.requires_app_restart) + true + } + } + if (preferences.defaultUserAgent().isSet()) { + preference { + key = "pref_reset_user_agent" + titleRes = R.string.pref_reset_user_agent_string + + onClick { + preferences.defaultUserAgent().delete() + activity?.toast(R.string.requires_app_restart) + } + } + } } preferenceCategory { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 49610e9d3..1d1453604 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -466,6 +466,8 @@ Network Clear cookies DNS over HTTPS (DoH) + Default user agent string + Reset default user agent string Requires app restart to take effect Cookies cleared Data From 8df8622dfa6d6779186e8ef3d4a8e90b6de71007 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Sat, 16 Jul 2022 17:21:27 -0400 Subject: [PATCH 09/34] Handle new default user agent where SY uses it (cherry picked from commit f3ffd3b930ba5d064bfac9138d15614f18d72c04) --- .../java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt | 6 +++--- app/src/main/java/exh/md/handlers/AzukiHandler.kt | 5 ++--- app/src/main/java/exh/md/handlers/ComikeyHandler.kt | 5 ++--- app/src/main/java/exh/md/handlers/MangaHotHandler.kt | 5 ++--- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt index 36ed09e5b..9e830121c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt @@ -121,16 +121,16 @@ class MangaDex(delegate: HttpSource, val context: Context) : MangaPlusHandler(network.client) } private val comikeyHandler by lazy { - ComikeyHandler(network.cloudflareClient) + ComikeyHandler(network.cloudflareClient, network.defaultUserAgent) } private val bilibiliHandler by lazy { BilibiliHandler(network.cloudflareClient) } private val azukHandler by lazy { - AzukiHandler(network.client) + AzukiHandler(network.client, network.defaultUserAgent) } private val mangaHotHandler by lazy { - MangaHotHandler(network.client) + MangaHotHandler(network.client, network.defaultUserAgent) } private val pageHandler by lazy { PageHandler( diff --git a/app/src/main/java/exh/md/handlers/AzukiHandler.kt b/app/src/main/java/exh/md/handlers/AzukiHandler.kt index fb8fa891e..dc54aa9c3 100644 --- a/app/src/main/java/exh/md/handlers/AzukiHandler.kt +++ b/app/src/main/java/exh/md/handlers/AzukiHandler.kt @@ -3,7 +3,6 @@ package exh.md.handlers import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.source.online.HttpSource import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject @@ -13,11 +12,11 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response -class AzukiHandler(currentClient: OkHttpClient) { +class AzukiHandler(currentClient: OkHttpClient, userAgent: String) { val baseUrl = "https://www.azuki.co" private val apiUrl = "https://production.api.azuki.co" val headers = Headers.Builder() - .add("User-Agent", HttpSource.DEFAULT_USER_AGENT) + .add("User-Agent", userAgent) .build() val client: OkHttpClient = currentClient diff --git a/app/src/main/java/exh/md/handlers/ComikeyHandler.kt b/app/src/main/java/exh/md/handlers/ComikeyHandler.kt index fbf5862a5..2f29887e6 100644 --- a/app/src/main/java/exh/md/handlers/ComikeyHandler.kt +++ b/app/src/main/java/exh/md/handlers/ComikeyHandler.kt @@ -3,7 +3,6 @@ package exh.md.handlers import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.asJsoup import kotlinx.serialization.json.Json import kotlinx.serialization.json.booleanOrNull @@ -16,11 +15,11 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response -class ComikeyHandler(cloudflareClient: OkHttpClient) { +class ComikeyHandler(cloudflareClient: OkHttpClient, userAgent: String) { val baseUrl = "https://comikey.com" private val apiUrl = "$baseUrl/sapi" val headers = Headers.Builder() - .add("User-Agent", HttpSource.DEFAULT_USER_AGENT) + .add("User-Agent", userAgent) .build() val client: OkHttpClient = cloudflareClient diff --git a/app/src/main/java/exh/md/handlers/MangaHotHandler.kt b/app/src/main/java/exh/md/handlers/MangaHotHandler.kt index e750f5d03..5b8580065 100644 --- a/app/src/main/java/exh/md/handlers/MangaHotHandler.kt +++ b/app/src/main/java/exh/md/handlers/MangaHotHandler.kt @@ -3,7 +3,6 @@ package exh.md.handlers import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.source.online.HttpSource import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject @@ -12,11 +11,11 @@ import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Response -class MangaHotHandler(currentClient: OkHttpClient) { +class MangaHotHandler(currentClient: OkHttpClient, userAgent: String) { val baseUrl = "https://mangahot.jp" private val apiUrl = "https://api.mangahot.jp" val headers = Headers.Builder() - .add("User-Agent", HttpSource.DEFAULT_USER_AGENT) + .add("User-Agent", userAgent) .build() val client: OkHttpClient = currentClient From 2ee6d2d90246c5bc9c0282939f9ef549709ee304 Mon Sep 17 00:00:00 2001 From: f1998f1998 <71004883+f1998f1998@users.noreply.github.com> Date: Mon, 18 Jul 2022 23:22:09 +0600 Subject: [PATCH 10/34] fix concurrent download (#7552) * Fix concurrent download * lower Concurrency * artist Update app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt Co-authored-by: Vetle Ledaal Co-authored-by: Vetle Ledaal (cherry picked from commit b635f02d93502f1021f0fe87533dfd96d052ed2f) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt (cherry picked from commit c69f53a8f4f0764b606c0d08a8d45bd1bc40bbbb) --- .../main/java/eu/kanade/tachiyomi/data/download/Downloader.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index a0049eb4c..6994b2b7b 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -347,8 +347,8 @@ class Downloader( // Get all the URLs to the source images, fetch pages if necessary .flatMap { download.source.fetchAllImageUrlsFromPageList(it) } // Start downloading images, consider we can have downloaded images already - // Concurrently do 5 pages at a time - .flatMap({ page -> getOrDownloadImage(page, download, tmpDir, dataSaver) }, 5) + // Concurrently do 2 pages at a time + .flatMap({ page -> getOrDownloadImage(page, download, tmpDir, dataSaver).subscribeOn(Schedulers.io()) }, 2) .onBackpressureLatest() // Do when page is downloaded. .doOnNext { notifier.onProgressChange(download) } From 06f0817bec10ee5119d385f1cd03a781b8355495 Mon Sep 17 00:00:00 2001 From: stevenyomi <95685115+stevenyomi@users.noreply.github.com> Date: Wed, 20 Jul 2022 21:10:41 +0800 Subject: [PATCH 11/34] Fix image MIME issues that cause download errors (#7562) * Downloader: ignore non-image MIME to prevent .bin extensions * ProgressResponseBody: allow null content type Co-authored-by: anenasa <84259093+anenasa@users.noreply.github.com> Co-authored-by: anenasa <84259093+anenasa@users.noreply.github.com> (cherry picked from commit 3547d0142f96c44da7fe1ee5bd6424fea679efa6) (cherry picked from commit d734993349196ee7fb5303cc73aaff8de0f9a3fd) --- .../main/java/eu/kanade/tachiyomi/data/download/Downloader.kt | 2 +- .../java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index 6994b2b7b..ad62aa85d 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -471,7 +471,7 @@ class Downloader( */ private fun getImageExtension(response: Response, file: UniFile): String { // Read content type if available. - val mime = response.body?.contentType()?.let { ct -> "${ct.type}/${ct.subtype}" } + val mime = response.body?.contentType()?.run { if (type == "image") "image/$subtype" else null } // Else guess from the uri. ?: context.contentResolver.getType(file.uri) // Else read magic numbers. diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt b/app/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt index ff56520b5..72248f17b 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt @@ -15,8 +15,8 @@ class ProgressResponseBody(private val responseBody: ResponseBody, private val p source(responseBody.source()).buffer() } - override fun contentType(): MediaType { - return responseBody.contentType()!! + override fun contentType(): MediaType? { + return responseBody.contentType() } override fun contentLength(): Long { From d52511d5ce0593be5935f48901bd5f9d5a596bcb Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Fri, 22 Jul 2022 08:23:59 +0600 Subject: [PATCH 12/34] Fix logic of app unlock (#7569) (cherry picked from commit 8ea05e852efd621ee987c7e45d6db64a083eeffd) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/App.kt (cherry picked from commit 09e5bcaec1916f4a2e846fc622749b092b10e994) --- app/src/main/java/eu/kanade/tachiyomi/App.kt | 2 ++ .../eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt | 2 +- .../kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt | 2 +- .../main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt | 2 -- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 2516f0bfa..797ae941b 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -72,6 +72,7 @@ import uy.kohesive.injekt.injectLazy import java.io.File import java.security.Security import java.text.SimpleDateFormat +import java.util.Date import java.util.Locale import kotlin.time.Duration.Companion.days @@ -182,6 +183,7 @@ open class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { } override fun onStop(owner: LifecycleOwner) { + preferences.lastAppClosed().set(Date().time) if (!AuthenticatorUtil.isAuthenticating && preferences.lockAppAfter().get() >= 0) { SecureActivityDelegate.locked = true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 5276dbdff..310324bb0 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -59,7 +59,7 @@ class PreferencesHelper(val context: Context) { fun lockAppAfter() = flowPrefs.getInt("lock_app_after", 0) - fun lastAppUnlock() = flowPrefs.getLong("last_app_unlock", 0) + fun lastAppClosed() = flowPrefs.getLong("last_app_closed", 0) fun secureScreen() = flowPrefs.getEnum("secure_screen_v2", Values.SecureScreenMode.INCOGNITO) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt index 20ae20e2d..0044348b0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt @@ -119,6 +119,6 @@ class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObser // SY <-- return preferences.lockAppAfter().get() <= 0 || - Date().time >= preferences.lastAppUnlock().get() + 60 * 1000 * preferences.lockAppAfter().get() + Date().time >= preferences.lastAppClosed().get() + 60 * 1000 * preferences.lockAppAfter().get() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt index a066bf64d..e33760af1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt @@ -10,7 +10,6 @@ import eu.kanade.tachiyomi.util.system.AuthenticatorUtil import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.startAuthentication import eu.kanade.tachiyomi.util.system.logcat import logcat.LogPriority -import java.util.Date /** * Blank activity with a BiometricPrompt. @@ -39,7 +38,6 @@ class UnlockActivity : BaseActivity() { ) { super.onAuthenticationSucceeded(activity, result) SecureActivityDelegate.locked = false - preferences.lastAppUnlock().set(Date().time) finish() } }, From 38b7240728656386da423778670d77f5f70bcf01 Mon Sep 17 00:00:00 2001 From: nzoba <55888232+nzoba@users.noreply.github.com> Date: Sat, 23 Jul 2022 00:55:31 +0200 Subject: [PATCH 13/34] Add downloaded icon in TransitionView when chapter is downloaded (#7575) * Add downloaded icon in TransitionView * Change icon (cherry picked from commit e8b7743826e9bf9aa0d15020b81ca0569cbe999d) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt (cherry picked from commit ea37a5a7a1bf351e7ec7958a0eeb08a1ca1e0a2d) --- .../ui/reader/viewer/ReaderTransitionView.kt | 75 +++++++++++++++---- .../viewer/pager/PagerTransitionHolder.kt | 2 +- .../ui/reader/viewer/pager/PagerViewer.kt | 4 + .../viewer/webtoon/WebtoonTransitionHolder.kt | 2 +- .../ui/reader/viewer/webtoon/WebtoonViewer.kt | 4 + .../main/res/drawable/ic_offline_pin_24dp.xml | 9 +++ 6 files changed, 79 insertions(+), 17 deletions(-) create mode 100644 app/src/main/res/drawable/ic_offline_pin_24dp.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt index 38786142a..c46a1fa9c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt @@ -1,15 +1,24 @@ package eu.kanade.tachiyomi.ui.reader.viewer import android.content.Context +import android.text.SpannableStringBuilder +import android.text.style.ImageSpan import android.util.AttributeSet import android.view.LayoutInflater import android.widget.LinearLayout +import androidx.core.content.ContextCompat import androidx.core.text.bold import androidx.core.text.buildSpannedString +import androidx.core.text.inSpans import androidx.core.view.isVisible import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.databinding.ReaderTransitionViewBinding +import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition +import eu.kanade.tachiyomi.util.system.dpToPx +import kotlin.math.roundToInt class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) { @@ -21,10 +30,11 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) } - fun bind(transition: ChapterTransition) { + fun bind(transition: ChapterTransition, downloadManager: DownloadManager, manga: Manga?) { + manga ?: return when (transition) { - is ChapterTransition.Prev -> bindPrevChapterTransition(transition) - is ChapterTransition.Next -> bindNextChapterTransition(transition) + is ChapterTransition.Prev -> bindPrevChapterTransition(transition, downloadManager, manga) + is ChapterTransition.Next -> bindNextChapterTransition(transition, downloadManager, manga) } missingChapterWarning(transition) } @@ -32,20 +42,32 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At /** * Binds a previous chapter transition on this view and subscribes to the page load status. */ - private fun bindPrevChapterTransition(transition: ChapterTransition) { - val prevChapter = transition.to + private fun bindPrevChapterTransition( + transition: ChapterTransition, + downloadManager: DownloadManager, + manga: Manga, + ) { + val prevChapter = transition.to?.chapter - val hasPrevChapter = prevChapter != null - binding.lowerText.isVisible = hasPrevChapter - if (hasPrevChapter) { + binding.lowerText.isVisible = prevChapter != null + if (prevChapter != null) { binding.upperText.textAlignment = TEXT_ALIGNMENT_TEXT_START + val isPrevDownloaded = downloadManager.isChapterDownloaded( + prevChapter.name, + prevChapter.scanlator, + manga.title, + manga.source, + ) + val isCurrentDownloaded = transition.from.pageLoader is DownloadPageLoader binding.upperText.text = buildSpannedString { bold { append(context.getString(R.string.transition_previous)) } - append("\n${prevChapter!!.chapter.name}") + append("\n${prevChapter.name}") + if (isPrevDownloaded) addDLImageSpan() } binding.lowerText.text = buildSpannedString { bold { append(context.getString(R.string.transition_current)) } append("\n${transition.from.chapter.name}") + if (isCurrentDownloaded) addDLImageSpan() } } else { binding.upperText.textAlignment = TEXT_ALIGNMENT_CENTER @@ -56,20 +78,32 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At /** * Binds a next chapter transition on this view and subscribes to the load status. */ - private fun bindNextChapterTransition(transition: ChapterTransition) { - val nextChapter = transition.to + private fun bindNextChapterTransition( + transition: ChapterTransition, + downloadManager: DownloadManager, + manga: Manga, + ) { + val nextChapter = transition.to?.chapter - val hasNextChapter = nextChapter != null - binding.lowerText.isVisible = hasNextChapter - if (hasNextChapter) { + binding.lowerText.isVisible = nextChapter != null + if (nextChapter != null) { binding.upperText.textAlignment = TEXT_ALIGNMENT_TEXT_START + val isCurrentDownloaded = transition.from.pageLoader is DownloadPageLoader + val isNextDownloaded = downloadManager.isChapterDownloaded( + nextChapter.name, + nextChapter.scanlator, + manga.title, + manga.source, + ) binding.upperText.text = buildSpannedString { bold { append(context.getString(R.string.transition_finished)) } append("\n${transition.from.chapter.name}") + if (isCurrentDownloaded) addDLImageSpan() } binding.lowerText.text = buildSpannedString { bold { append(context.getString(R.string.transition_next)) } - append("\n${nextChapter!!.chapter.name}") + append("\n${nextChapter.name}") + if (isNextDownloaded) addDLImageSpan() } } else { binding.upperText.textAlignment = TEXT_ALIGNMENT_CENTER @@ -77,6 +111,17 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At } } + private fun SpannableStringBuilder.addDLImageSpan() { + val icon = ContextCompat.getDrawable(context, R.drawable.ic_offline_pin_24dp)?.mutate() + ?.apply { + val size = binding.lowerText.textSize + 4.dpToPx + setTint(binding.lowerText.currentTextColor) + setBounds(0, 0, size.roundToInt(), size.roundToInt()) + } ?: return + append(" ") + inSpans(ImageSpan(icon)) { append("image") } + } + private fun missingChapterWarning(transition: ChapterTransition) { if (transition.to == null) { binding.warning.isVisible = false diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt index 9f712c2da..4445923d8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt @@ -61,7 +61,7 @@ class PagerTransitionHolder( addView(transitionView) addView(pagesContainer) - transitionView.bind(transition) + transitionView.bind(transition, viewer.downloadManager, viewer.activity.presenter.manga) transition.to?.let { observeStatus(it) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt index 54c642e26..c0b639d99 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt @@ -11,6 +11,7 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.viewpager.widget.ViewPager import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition import eu.kanade.tachiyomi.ui.reader.model.InsertPage @@ -21,6 +22,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation.NavigationRegion import eu.kanade.tachiyomi.util.system.logcat import kotlinx.coroutines.MainScope import kotlinx.coroutines.cancel +import uy.kohesive.injekt.injectLazy import kotlin.math.min /** @@ -29,6 +31,8 @@ import kotlin.math.min @Suppress("LeakingThis") abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { + val downloadManager: DownloadManager by injectLazy() + val scope = MainScope() /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonTransitionHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonTransitionHolder.kt index c905f1275..67e9b5b1d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonTransitionHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonTransitionHolder.kt @@ -63,7 +63,7 @@ class WebtoonTransitionHolder( * Binds the given [transition] with this view holder, subscribing to its state. */ fun bind(transition: ChapterTransition) { - transitionView.bind(transition) + transitionView.bind(transition, viewer.downloadManager, viewer.activity.presenter.manga) transition.to?.let { observeStatus(it, transition) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index 46b4e69b5..53ed73b07 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -11,6 +11,7 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.WebtoonLayoutManager +import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition @@ -24,6 +25,7 @@ import kotlinx.coroutines.cancel import rx.subscriptions.CompositeSubscription import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import uy.kohesive.injekt.injectLazy import kotlin.math.max import kotlin.math.min @@ -32,6 +34,8 @@ import kotlin.math.min */ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true, private val tapByPage: Boolean = false) : BaseViewer { + val downloadManager: DownloadManager by injectLazy() + private val scope = MainScope() /** diff --git a/app/src/main/res/drawable/ic_offline_pin_24dp.xml b/app/src/main/res/drawable/ic_offline_pin_24dp.xml new file mode 100644 index 000000000..9a9cc213f --- /dev/null +++ b/app/src/main/res/drawable/ic_offline_pin_24dp.xml @@ -0,0 +1,9 @@ + + + From 43010e92ac29d8988a3fa3a6c30397053f0cc393 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 23 Jul 2022 11:13:52 -0400 Subject: [PATCH 14/34] Show better error when trying to open RARv5 file (cherry picked from commit a84305438853cafa9aff194b89fa221603f2f743) (cherry picked from commit 53a381ce285f166a8e2e6c635cf71c0bbc662938) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt --- .../eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt | 7 ++++++- app/src/main/res/values/strings.xml | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt index 224759e60..8501d60fe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.reader.loader import android.content.Context +import com.github.junrar.exception.UnsupportedRarV5Exception import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.download.DownloadManager @@ -116,7 +117,11 @@ class ChapterLoader( when (format) { is LocalSource.Format.Directory -> DirectoryPageLoader(format.file) is LocalSource.Format.Zip -> ZipPageLoader(format.file) - is LocalSource.Format.Rar -> RarPageLoader(format.file) + is LocalSource.Format.Rar -> try { + RarPageLoader(format.file) + } catch (e: UnsupportedRarV5Exception) { + error(context.getString(R.string.loader_rar5_error)) + } is LocalSource.Format.Epub -> EpubPageLoader(format.file) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d1453604..f80edb54b 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -702,6 +702,7 @@ Failed to load pages: %1$s No pages found Source not found + RARv5 format is not supported Skipping %d chapter, either the source is missing it or it has been filtered out Skipping %d chapters, either the source is missing them or they have been filtered out From 474eea1c845de175ca6ab95b251da33a747a9c56 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 23 Jul 2022 11:14:34 -0400 Subject: [PATCH 15/34] Avoid catastrophic failure when cover can't be created in local source (fixes #7577) (cherry picked from commit d6977e5676377f6090c0e0b4eb15fd043fa01e11) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt (cherry picked from commit cfe78ff907378fe39aa72227c718f96f4ac4ad3b) --- .../eu/kanade/tachiyomi/source/LocalSource.kt | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt index bc580147a..d62d9c2ab 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt @@ -4,7 +4,6 @@ import android.content.Context import com.github.junrar.Archive import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList @@ -20,16 +19,16 @@ import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.EpubFile import eu.kanade.tachiyomi.util.system.ImageUtil +import eu.kanade.tachiyomi.util.system.logcat import kotlinx.coroutines.runBlocking import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream import kotlinx.serialization.json.encodeToStream +import logcat.LogPriority import rx.Observable import tachiyomi.source.model.ChapterInfo import tachiyomi.source.model.MangaInfo -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import java.io.File import java.io.FileInputStream @@ -39,7 +38,6 @@ import java.util.zip.ZipFile class LocalSource( private val context: Context, - private val coverCache: CoverCache = Injekt.get(), ) : CatalogueSource, UnmeteredSource { private val json: Json by injectLazy() @@ -286,41 +284,46 @@ class LocalSource( } private fun updateCover(chapter: SChapter, manga: SManga): File? { - return when (val format = getFormat(chapter)) { - is Format.Directory -> { - val entry = format.file.listFiles() - ?.sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) } - ?.find { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } } + return try { + when (val format = getFormat(chapter)) { + is Format.Directory -> { + val entry = format.file.listFiles() + ?.sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) } + ?.find { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } } - entry?.let { updateCover(context, manga, it.inputStream()) } - } - is Format.Zip -> { - ZipFile(format.file).use { zip -> - val entry = zip.entries().toList() - .sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) } - .find { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } + entry?.let { updateCover(context, manga, it.inputStream()) } + } + is Format.Zip -> { + ZipFile(format.file).use { zip -> + val entry = zip.entries().toList() + .sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) } + .find { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } - entry?.let { updateCover(context, manga, zip.getInputStream(it)) } - } - } - is Format.Rar -> { - Archive(format.file).use { archive -> - val entry = archive.fileHeaders - .sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) } - .find { !it.isDirectory && ImageUtil.isImage(it.fileName) { archive.getInputStream(it) } } - - entry?.let { updateCover(context, manga, archive.getInputStream(it)) } - } - } - is Format.Epub -> { - EpubFile(format.file).use { epub -> - val entry = epub.getImagesFromPages() - .firstOrNull() - ?.let { epub.getEntry(it) } - - entry?.let { updateCover(context, manga, epub.getInputStream(it)) } + entry?.let { updateCover(context, manga, zip.getInputStream(it)) } + } + } + is Format.Rar -> { + Archive(format.file).use { archive -> + val entry = archive.fileHeaders + .sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) } + .find { !it.isDirectory && ImageUtil.isImage(it.fileName) { archive.getInputStream(it) } } + + entry?.let { updateCover(context, manga, archive.getInputStream(it)) } + } + } + is Format.Epub -> { + EpubFile(format.file).use { epub -> + val entry = epub.getImagesFromPages() + .firstOrNull() + ?.let { epub.getEntry(it) } + + entry?.let { updateCover(context, manga, epub.getInputStream(it)) } + } } } + } catch (e: Throwable) { + logcat(LogPriority.ERROR, e) { "Error updating cover for ${manga.title}" } + null } .also { coverCache.clearMemoryCache() } } @@ -398,7 +401,6 @@ class LocalSource( } } - // Create a .nomedia file DiskUtil.createNoMediaFile(UniFile.fromFile(mangaDir), context) manga.thumbnail_url = coverFile.absolutePath From 9a5ea9b5073c36af551380ce428c7ef83837bb88 Mon Sep 17 00:00:00 2001 From: MatchaSoba <76941874+MatchaSoba@users.noreply.github.com> Date: Sat, 30 Jul 2022 23:53:25 +0800 Subject: [PATCH 16/34] Fix logic for searchWithGenre (#7559) (cherry picked from commit b563e85c3b744595272718f7e82e3272e2a7c57b) (cherry picked from commit b729b7f0aa11780ada0a7056c153f8c6ef67d864) --- .../source/browse/BrowseSourceController.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt index 2fc32e41d..488cb6689 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt @@ -483,11 +483,11 @@ open class BrowseSourceController(bundle: Bundle) : * @param genreName the name of the genre */ fun searchWithGenre(genreName: String) { - presenter.sourceFilters = presenter.source.getFilterList() + val defaultFilters = presenter.source.getFilterList() - var filterList: FilterList? = null + var genreExists = false - filter@ for (sourceFilter in presenter.sourceFilters) { + filter@ for (sourceFilter in defaultFilters) { if (sourceFilter is Filter.Group<*>) { for (filter in sourceFilter.state) { if (filter is Filter<*> && filter.name.equals(genreName, true)) { @@ -496,7 +496,7 @@ open class BrowseSourceController(bundle: Bundle) : is Filter.CheckBox -> filter.state = true else -> {} } - filterList = presenter.sourceFilters + genreExists = true break@filter } } @@ -506,19 +506,20 @@ open class BrowseSourceController(bundle: Bundle) : if (index != -1) { sourceFilter.state = index - filterList = presenter.sourceFilters + genreExists = true break } } } - if (filterList != null) { + if (genreExists) { + presenter.sourceFilters = defaultFilters filterSheet?.setFilters(presenter.filterItems) showProgressBar() adapter?.clear() - presenter.restartPager("", filterList) + presenter.restartPager("", defaultFilters) } else { searchWithQuery(genreName) } From 9a577e1c693ba3b456b6d2f18540dae6ec35421c Mon Sep 17 00:00:00 2001 From: Andreas Date: Sun, 31 Jul 2022 17:17:43 +0200 Subject: [PATCH 17/34] Remove deprecated LibrarySort (#7659) * Remove deprecated LibrarySort * Apply suggestions from code review (cherry picked from commit 58acf0a8aa3aa37b5d9c63d99987a05ee2f8790f) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt (cherry picked from commit 4b87831bdd125bbd7c6f2cbddcab97279d71933b) # Conflicts: # app/src/main/java/exh/EXHMigrations.kt --- .../java/eu/kanade/tachiyomi/Migrations.kt | 23 ++++---- .../tachiyomi/ui/library/LibrarySort.kt | 23 -------- app/src/main/java/exh/EXHMigrations.kt | 57 ++++++++++--------- 3 files changed, 40 insertions(+), 63 deletions(-) delete mode 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index 0a90453a4..126fbeffe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.updater.AppUpdateJob import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE -import eu.kanade.tachiyomi.ui.library.LibrarySort import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting import eu.kanade.tachiyomi.ui.reader.setting.OrientationType @@ -106,10 +105,9 @@ object Migrations { // Reset sorting preference if using removed sort by source val oldSortingMode = prefs.getInt(PreferenceKeys.librarySortingMode, 0) - @Suppress("DEPRECATION") - if (oldSortingMode == LibrarySort.SOURCE) { + if (oldSortingMode == 5 /* SOURCE */) { prefs.edit { - putInt(PreferenceKeys.librarySortingMode, LibrarySort.ALPHA) + putInt(PreferenceKeys.librarySortingMode, 0 /* ALPHABETICAL */) } } } @@ -202,16 +200,15 @@ object Migrations { val oldSortingMode = prefs.getInt(PreferenceKeys.librarySortingMode, 0) val oldSortingDirection = prefs.getBoolean(PreferenceKeys.librarySortingDirection, true) - @Suppress("DEPRECATION") val newSortingMode = when (oldSortingMode) { - LibrarySort.ALPHA -> SortModeSetting.ALPHABETICAL - LibrarySort.LAST_READ -> SortModeSetting.LAST_READ - LibrarySort.LAST_CHECKED -> SortModeSetting.LAST_CHECKED - LibrarySort.UNREAD -> SortModeSetting.UNREAD - LibrarySort.TOTAL -> SortModeSetting.TOTAL_CHAPTERS - LibrarySort.LATEST_CHAPTER -> SortModeSetting.LATEST_CHAPTER - LibrarySort.CHAPTER_FETCH_DATE -> SortModeSetting.DATE_FETCHED - LibrarySort.DATE_ADDED -> SortModeSetting.DATE_ADDED + 0 -> SortModeSetting.ALPHABETICAL + 1 -> SortModeSetting.LAST_READ + 2 -> SortModeSetting.LAST_CHECKED + 3 -> SortModeSetting.UNREAD + 4 -> SortModeSetting.TOTAL_CHAPTERS + 6 -> SortModeSetting.LATEST_CHAPTER + 8 -> SortModeSetting.DATE_FETCHED + 7 -> SortModeSetting.DATE_ADDED else -> SortModeSetting.ALPHABETICAL } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt deleted file mode 100755 index 98792740f..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt +++ /dev/null @@ -1,23 +0,0 @@ -package eu.kanade.tachiyomi.ui.library - -@Deprecated("Deprecated in favor for SortModeSetting") -object LibrarySort { - - const val ALPHA = 0 - const val LAST_READ = 1 - const val LAST_CHECKED = 2 - const val UNREAD = 3 - const val TOTAL = 4 - const val LATEST_CHAPTER = 6 - const val CHAPTER_FETCH_DATE = 10 - const val DATE_ADDED = 8 - - // SY --> - const val DRAG_AND_DROP = 7 - const val TAG_LIST = 9 - - // SY <-- - - @Deprecated("Removed in favor of searching by source") - const val SOURCE = 5 -} diff --git a/app/src/main/java/exh/EXHMigrations.kt b/app/src/main/java/exh/EXHMigrations.kt index 80b1fffd8..fcf49c066 100644 --- a/app/src/main/java/exh/EXHMigrations.kt +++ b/app/src/main/java/exh/EXHMigrations.kt @@ -31,7 +31,6 @@ import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.all.Hitomi import eu.kanade.tachiyomi.source.online.all.NHentai -import eu.kanade.tachiyomi.ui.library.LibrarySort import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting @@ -308,36 +307,40 @@ object EXHMigrations { } } if (oldVersion under 20) { - val oldSortingMode = prefs.getInt(PreferenceKeys.librarySortingMode, 0) - val oldSortingDirection = prefs.getBoolean(PreferenceKeys.librarySortingDirection, true) + try { + val oldSortingMode = prefs.getInt(PreferenceKeys.librarySortingMode, 0 /* ALPHABETICAL */) + val oldSortingDirection = prefs.getBoolean(PreferenceKeys.librarySortingDirection, true) - val newSortingMode = when (oldSortingMode) { - LibrarySort.ALPHA -> SortModeSetting.ALPHABETICAL - LibrarySort.LAST_READ -> SortModeSetting.LAST_READ - LibrarySort.LAST_CHECKED -> SortModeSetting.LAST_CHECKED - LibrarySort.UNREAD -> SortModeSetting.UNREAD - LibrarySort.TOTAL -> SortModeSetting.TOTAL_CHAPTERS - LibrarySort.LATEST_CHAPTER -> SortModeSetting.LATEST_CHAPTER - LibrarySort.CHAPTER_FETCH_DATE -> SortModeSetting.DATE_FETCHED - LibrarySort.DATE_ADDED -> SortModeSetting.DATE_ADDED - LibrarySort.DRAG_AND_DROP -> SortModeSetting.DRAG_AND_DROP - LibrarySort.TAG_LIST -> SortModeSetting.TAG_LIST - else -> SortModeSetting.ALPHABETICAL - } + val newSortingMode = when (oldSortingMode) { + 0 -> SortModeSetting.ALPHABETICAL + 1 -> SortModeSetting.LAST_READ + 2 -> SortModeSetting.LAST_MANGA_UPDATE + 3 -> SortModeSetting.UNREAD_COUNT + 4 -> SortModeSetting.TOTAL_CHAPTERS + 6 -> SortModeSetting.LATEST_CHAPTER + 7 -> SortModeSetting.DRAG_AND_DROP + 8 -> SortModeSetting.DATE_ADDED + 9 -> SortModeSetting.TAG_LIST + 10 -> SortModeSetting.CHAPTER_FETCH_DATE + else -> SortModeSetting.ALPHABETICAL + } - val newSortingDirection = when (oldSortingDirection) { - true -> SortDirectionSetting.ASCENDING - else -> SortDirectionSetting.DESCENDING - } + val newSortingDirection = when (oldSortingDirection) { + true -> SortDirectionSetting.ASCENDING + else -> SortDirectionSetting.DESCENDING + } - prefs.edit(commit = true) { - remove(PreferenceKeys.librarySortingMode) - remove(PreferenceKeys.librarySortingDirection) - } + prefs.edit(commit = true) { + remove(PreferenceKeys.librarySortingMode) + remove(PreferenceKeys.librarySortingDirection) + } - prefs.edit { - putString(PreferenceKeys.librarySortingMode, newSortingMode.name) - putString(PreferenceKeys.librarySortingDirection, newSortingDirection.name) + prefs.edit { + putString(PreferenceKeys.librarySortingMode, newSortingMode.name) + putString(PreferenceKeys.librarySortingDirection, newSortingDirection.name) + } + } catch (e: Exception) { + logcat(throwable = e) { "Already done migration" } } } if (oldVersion under 21) { From 71db4eebeac1e079f8ad198c1361e0489cebe3c8 Mon Sep 17 00:00:00 2001 From: stevenyomi <95685115+stevenyomi@users.noreply.github.com> Date: Sun, 31 Jul 2022 23:18:12 +0800 Subject: [PATCH 18/34] Filter out empty genres before saving manga to database (#7655) (cherry picked from commit 4efb736e56dd1e9f6438502dac915467f5b64f03) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt # app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt (cherry picked from commit 702fdb054a0a30f4bbd9e43c211d978d297871e9) --- .../java/eu/kanade/tachiyomi/data/database/models/Manga.kt | 5 ----- .../main/java/eu/kanade/tachiyomi/source/model/SManga.kt | 7 ++++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt index 4fa3a1449..a5aa2857d 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt @@ -34,11 +34,6 @@ interface Manga : SManga { return chapter_flags and CHAPTER_SORT_MASK == CHAPTER_SORT_DESC } - fun getGenres(): List? { - if (genre.isNullOrBlank()) return null - return genre?.split(", ")?.map { it.trim() }?.filterNot { it.isBlank() }?.distinct() - } - // SY --> fun getOriginalGenres(): List? { return originalGenre?.split(", ")?.map { it.trim() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt index f7ead6db2..64cc824f9 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt @@ -28,6 +28,11 @@ interface SManga : Serializable { var initialized: Boolean + fun getGenres(): List? { + if (genre.isNullOrBlank()) return null + return genre?.split(", ")?.map { it.trim() }?.filterNot { it.isBlank() }?.distinct() + } + // SY --> val originalTitle: String get() = (this as? MangaImpl)?.ogTitle ?: title @@ -104,7 +109,7 @@ fun SManga.toMangaInfo(): MangaInfo { artist = this.artist ?: "", author = this.author ?: "", description = this.description ?: "", - genres = this.genre?.split(", ") ?: emptyList(), + genres = this.getGenres() ?: emptyList(), status = this.status, cover = this.thumbnail_url ?: "", ) From 214cbed3f0dce720e75fa7a344ca7b6e2e61e0bd Mon Sep 17 00:00:00 2001 From: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Date: Thu, 4 Aug 2022 23:17:43 -0300 Subject: [PATCH 19/34] Add missing `Authorization` header on MAL refresh token request (#7686) * Add missing Authorization header on MAL refresh token request. * Make sure to also close the response when it have failed. (cherry picked from commit 531546790853dd9adb91777de8d9560a610c4838) (cherry picked from commit af1ee662eda12d96f27e2f06af9f168f86cdee4c) --- .../data/track/myanimelist/MyAnimeListApi.kt | 15 ++++++++++++--- .../myanimelist/MyAnimeListInterceptor.kt | 19 ++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt index 5eef11d57..13d13acbb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt @@ -22,6 +22,7 @@ import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive import okhttp3.FormBody +import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody @@ -256,13 +257,21 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI .appendPath("my_list_status") .build() - fun refreshTokenRequest(refreshToken: String): Request { + fun refreshTokenRequest(oauth: OAuth): Request { val formBody: RequestBody = FormBody.Builder() .add("client_id", clientId) - .add("refresh_token", refreshToken) + .add("refresh_token", oauth.refresh_token) .add("grant_type", "refresh_token") .build() - return POST("$baseOAuthUrl/token", body = formBody) + + // Add the Authorization header manually as this particular + // request is called by the interceptor itself so it doesn't reach + // the part where the token is added automatically. + val headers = Headers.Builder() + .add("Authorization", "Bearer ${oauth.access_token}") + .build() + + return POST("$baseOAuthUrl/token", body = formBody, headers = headers) } private fun getPkceChallengeCode(): String { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt index 571b9a59f..22da4c121 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt @@ -1,9 +1,11 @@ package eu.kanade.tachiyomi.data.track.myanimelist +import eu.kanade.tachiyomi.network.parseAs import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import okhttp3.Interceptor import okhttp3.Response +import okhttp3.internal.closeQuietly import uy.kohesive.injekt.injectLazy import java.io.IOException @@ -24,11 +26,22 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList, private var t } // Refresh access token if expired if (oauth != null && oauth!!.isExpired()) { - chain.proceed(MyAnimeListApi.refreshTokenRequest(oauth!!.refresh_token)).use { - if (it.isSuccessful) { - setAuth(json.decodeFromString(it.body!!.string())) + val newOauth = runCatching { + val oauthResponse = chain.proceed(MyAnimeListApi.refreshTokenRequest(oauth!!)) + + if (oauthResponse.isSuccessful) { + oauthResponse.parseAs() + } else { + oauthResponse.closeQuietly() + null } } + + if (newOauth.getOrNull() == null) { + throw IOException("Failed to refresh the access token") + } + + setAuth(newOauth.getOrNull()) } if (oauth == null) { throw IOException("No authentication token") From 5f7b7c652cb24e46a9709d2fdcbc34352ff8e46b Mon Sep 17 00:00:00 2001 From: Andreas Date: Wed, 10 Aug 2022 21:53:47 +0200 Subject: [PATCH 20/34] Log extension loading errors directly (#7716) (cherry picked from commit 7892cc1519ef0ecf0dc0b519a0df8806eba05e99) (cherry picked from commit 0b7d0f7f6727e46e21bd01c4a25968096108e8fd) --- .../tachiyomi/extension/model/LoadResult.kt | 4 +--- .../util/ExtensionInstallReceiver.kt | 7 ++++++- .../extension/util/ExtensionLoader.kt | 21 ++++++++++++------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/model/LoadResult.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/model/LoadResult.kt index 0cf470fe8..f1982b2f2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/model/LoadResult.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/model/LoadResult.kt @@ -4,7 +4,5 @@ sealed class LoadResult { class Success(val extension: Extension.Installed) : LoadResult() class Untrusted(val extension: Extension.Untrusted) : LoadResult() - class Error(val message: String? = null) : LoadResult() { - constructor(exception: Throwable) : this(exception.message) - } + object Error : LoadResult() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt index 943e82845..08bea8ff9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt @@ -7,10 +7,12 @@ import android.content.IntentFilter import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.LoadResult import eu.kanade.tachiyomi.util.lang.launchNow +import eu.kanade.tachiyomi.util.system.logcat import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async +import logcat.LogPriority /** * Broadcast receiver that listens for the system's packages installed, updated or removed, and only @@ -94,7 +96,10 @@ internal class ExtensionInstallReceiver(private val listener: Listener) : */ private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): LoadResult { val pkgName = getPackageNameFromIntent(intent) - ?: return LoadResult.Error("Package name not found") + if (pkgName == null) { + logcat(LogPriority.WARN) { "Package name not found" } + return LoadResult.Error + } return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) { ExtensionLoader.loadExtensionFromPkgName(context, pkgName) }.await() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt index 240cb1f65..6d5f763bc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt @@ -80,10 +80,12 @@ internal object ExtensionLoader { context.packageManager.getPackageInfo(pkgName, PACKAGE_FLAGS) } catch (error: PackageManager.NameNotFoundException) { // Unlikely, but the package may have been uninstalled at this point - return LoadResult.Error(error) + logcat(LogPriority.ERROR, error) + return LoadResult.Error } if (!isPackageAnExtension(pkgInfo)) { - return LoadResult.Error("Tried to load a package that wasn't a extension") + logcat(LogPriority.WARN) { "Tried to load a package that wasn't a extension ($pkgName)" } + return LoadResult.Error } return loadExtension(context, pkgName, pkgInfo) } @@ -102,7 +104,8 @@ internal object ExtensionLoader { pkgManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA) } catch (error: PackageManager.NameNotFoundException) { // Unlikely, but the package may have been uninstalled at this point - return LoadResult.Error(error) + logcat(LogPriority.ERROR, error) + return LoadResult.Error } val extName = pkgManager.getApplicationLabel(appInfo).toString().substringAfter("Tachiyomi: ") @@ -112,7 +115,7 @@ internal object ExtensionLoader { if (versionName.isNullOrEmpty()) { val exception = Exception("Missing versionName for extension $extName") logcat(LogPriority.WARN, exception) - return LoadResult.Error(exception) + return LoadResult.Error } // Validate lib version @@ -123,13 +126,14 @@ internal object ExtensionLoader { "$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed", ) logcat(LogPriority.WARN, exception) - return LoadResult.Error(exception) + return LoadResult.Error } val signatureHash = getSignatureHash(pkgInfo) if (signatureHash == null) { - return LoadResult.Error("Package $pkgName isn't signed") + logcat(LogPriority.WARN) { "Package $pkgName isn't signed" } + return LoadResult.Error } else if (signatureHash !in trustedSignatures) { val extension = Extension.Untrusted(extName, pkgName, versionName, versionCode, signatureHash) logcat(LogPriority.WARN) { "Extension $pkgName isn't trusted" } @@ -138,7 +142,8 @@ internal object ExtensionLoader { val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1 if (!loadNsfwSource && isNsfw) { - return LoadResult.Error("NSFW extension $pkgName not allowed") + logcat(LogPriority.WARN) { "NSFW extension $pkgName not allowed" } + return LoadResult.Error } val hasReadme = appInfo.metaData.getInt(METADATA_HAS_README, 0) == 1 @@ -165,7 +170,7 @@ internal object ExtensionLoader { } } catch (e: Throwable) { logcat(LogPriority.ERROR, e) { "Extension load error: $extName ($it)" } - return LoadResult.Error(e) + return LoadResult.Error } } From f322a7e660a6d8b75f8d8c22a6eb9118514acd85 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 13 Aug 2022 14:56:08 -0400 Subject: [PATCH 21/34] Add auto split tall images setting Also includes some fixes for bad merges in earlier commits Co-authored-by: Saud-97 Co-authored-by: AntsyLich (cherry picked from commit 6db2becd3023046558c1100a6658a8a76eac1148) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt # app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt --- .../tachiyomi/data/download/Downloader.kt | 46 +++-- .../data/preference/PreferencesHelper.kt | 2 + .../myanimelist/MyAnimeListInterceptor.kt | 1 - .../eu/kanade/tachiyomi/source/LocalSource.kt | 4 + .../ui/reader/viewer/pager/PagerPageHolder.kt | 5 +- .../viewer/webtoon/WebtoonPageHolder.kt | 5 +- .../ui/setting/SettingsDownloadController.kt | 7 + .../util/system/ContextExtensions.kt | 12 +- .../kanade/tachiyomi/util/system/ImageUtil.kt | 177 +++++++++++++++--- app/src/main/res/values/strings.xml | 5 + 10 files changed, 216 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index ad62aa85d..94496acc6 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -275,7 +275,7 @@ class Downloader( // Start downloader if needed if (autoStart && wasEmpty) { - val queuedDownloads = queue.filter { it.source !is UnmeteredSource }.count() + val queuedDownloads = queue.count { it.source !is UnmeteredSource } val maxDownloadsFromSource = queue .groupBy { it.source } .filterKeys { it !is UnmeteredSource } @@ -358,6 +358,7 @@ class Downloader( .doOnNext { ensureSuccessfulDownload(download, mangaDir, tmpDir, chapterDirname) } // If the page list threw, it will resume here .onErrorReturn { error -> + logcat(LogPriority.ERROR, error) download.status = Download.State.ERROR notifier.onError(error.message, download.chapter.name, download.manga.title) download @@ -385,7 +386,7 @@ class Downloader( tmpFile?.delete() // Try to find the image file. - val imageFile = tmpDir.listFiles()!!.find { it.name!!.startsWith("$filename.") } + val imageFile = tmpDir.listFiles()!!.find { it.name!!.startsWith("$filename.") || it.name!!.contains("${filename}__001") } // If the image is already downloaded, do nothing. Otherwise download from network val pageObservable = when { @@ -395,8 +396,12 @@ class Downloader( } return pageObservable - // When the image is ready, set image path, progress (just in case) and status + // When the page is ready, set page path, progress (just in case) and status .doOnNext { file -> + val success = splitTallImageIfNeeded(page, tmpDir) + if (success.not()) { + notifier.onError(context.getString(R.string.download_notifier_split_failed), download.chapter.name, download.manga.title) + } page.uri = file.uri page.progress = 100 download.downloadedImages++ @@ -407,6 +412,7 @@ class Downloader( .onErrorReturn { page.progress = 0 page.status = Page.ERROR + notifier.onError(it.message, download.chapter.name, download.manga.title) page } } @@ -480,6 +486,26 @@ class Downloader( return ImageUtil.getExtensionFromMimeType(mime) } + private fun splitTallImageIfNeeded(page: Page, tmpDir: UniFile): Boolean { + if (!preferences.splitTallImages().get()) return true + + val filename = String.format("%03d", page.number) + val imageFile = tmpDir.listFiles()?.find { it.name!!.startsWith(filename) } + ?: throw Error(context.getString(R.string.download_notifier_split_page_not_found, page.number)) + val imageFilePath = imageFile.filePath + ?: throw Error(context.getString(R.string.download_notifier_split_page_path_not_found, page.number)) + + // check if the original page was previously splitted before then skip. + if (imageFile.name!!.contains("__")) return true + + return try { + ImageUtil.splitTallImage(imageFile, imageFilePath) + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + false + } + } + /** * Checks if the download was successful. * @@ -495,16 +521,10 @@ class Downloader( dirname: String, ) { // Ensure that the chapter folder has all the images. - val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") } + val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") || (it.name!!.contains("__") && !it.name!!.contains("__001.jpg")) } download.status = if (downloadedImages.size == download.pages!!.size) { - Download.State.DOWNLOADED - } else { - Download.State.ERROR - } - - // Only rename the directory if it's downloaded. - if (download.status == Download.State.DOWNLOADED) { + // Only rename the directory if it's downloaded. if (preferences.saveChaptersAsCBZ().get()) { archiveChapter(mangaDir, dirname, tmpDir) } else { @@ -513,6 +533,10 @@ class Downloader( cache.addChapter(dirname, mangaDir, download.manga) DiskUtil.createNoMediaFile(tmpDir, context) + + Download.State.DOWNLOADED + } else { + Download.State.ERROR } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 310324bb0..8bf9defe7 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -215,6 +215,8 @@ class PreferencesHelper(val context: Context) { fun saveChaptersAsCBZ() = flowPrefs.getBoolean("save_chapter_as_cbz", true) + fun splitTallImages() = flowPrefs.getBoolean("split_tall_images", false) + fun folderPerManga() = prefs.getBoolean(Keys.folderPerManga, false) fun numberOfBackups() = flowPrefs.getInt("backup_slots", 2) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt index 22da4c121..cf26d57e8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.data.track.myanimelist import eu.kanade.tachiyomi.network.parseAs -import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import okhttp3.Interceptor import okhttp3.Response diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt index d62d9c2ab..6373f5672 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt @@ -4,6 +4,7 @@ import android.content.Context import com.github.junrar.Archive import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList @@ -29,6 +30,8 @@ import logcat.LogPriority import rx.Observable import tachiyomi.source.model.ChapterInfo import tachiyomi.source.model.MangaInfo +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import java.io.File import java.io.FileInputStream @@ -38,6 +41,7 @@ import java.util.zip.ZipFile class LocalSource( private val context: Context, + private val coverCache: CoverCache = Injekt.get(), ) : CatalogueSource, UnmeteredSource { private val json: Json by injectLazy() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt index 8bad040a0..e8d048701 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt @@ -24,6 +24,7 @@ import rx.Subscription import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers import tachiyomi.decoder.ImageDecoder +import java.io.BufferedInputStream import java.io.ByteArrayInputStream import java.io.InputStream import java.util.concurrent.TimeUnit @@ -332,7 +333,7 @@ class PagerPageHolder( .subscribe({}, {}) } - private fun process(page: ReaderPage, imageStream: InputStream): InputStream { + private fun process(page: ReaderPage, imageStream: BufferedInputStream): InputStream { if (!viewer.config.dualPageSplit) { return imageStream } @@ -341,7 +342,7 @@ class PagerPageHolder( return splitInHalf(imageStream) } - val isDoublePage = ImageUtil.isDoublePage(imageStream) + val isDoublePage = ImageUtil.isWideImage(imageStream) if (!isDoublePage) { return imageStream } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt index 1b9abf6c7..c8ce89ab0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt @@ -23,6 +23,7 @@ import rx.Observable import rx.Subscription import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers +import java.io.BufferedInputStream import java.io.InputStream import java.util.concurrent.TimeUnit @@ -272,12 +273,12 @@ class WebtoonPageHolder( addSubscription(readImageHeaderSubscription) } - private fun process(imageStream: InputStream): InputStream { + private fun process(imageStream: BufferedInputStream): InputStream { if (!viewer.config.dualPageSplit) { return imageStream } - val isDoublePage = ImageUtil.isDoublePage(imageStream) + val isDoublePage = ImageUtil.isWideImage(imageStream) if (!isDoublePage) { return imageStream } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt index 74fce340b..eaf43573e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt @@ -24,6 +24,7 @@ import eu.kanade.tachiyomi.util.preference.multiSelectListPreference import eu.kanade.tachiyomi.util.preference.onClick import eu.kanade.tachiyomi.util.preference.preference import eu.kanade.tachiyomi.util.preference.preferenceCategory +import eu.kanade.tachiyomi.util.preference.summaryRes import eu.kanade.tachiyomi.util.preference.switchPreference import eu.kanade.tachiyomi.util.preference.titleRes import eu.kanade.tachiyomi.util.system.toast @@ -72,6 +73,12 @@ class SettingsDownloadController : SettingsController() { bindTo(preferences.saveChaptersAsCBZ()) titleRes = R.string.save_chapter_as_cbz } + switchPreference { + bindTo(preferences.splitTallImages()) + titleRes = R.string.split_tall_images + summaryRes = R.string.split_tall_images_summary + } + preferenceCategory { titleRes = R.string.pref_category_delete_chapters diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt index d9a76d31e..b04121003 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt @@ -47,6 +47,7 @@ import logcat.LogPriority import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.io.File +import kotlin.math.max import kotlin.math.roundToInt private const val TABLET_UI_MIN_SCREEN_WIDTH_DP = 720 @@ -166,6 +167,9 @@ fun Context.hasPermission(permission: String) = ContextCompat.checkSelfPermissio } } +val getDisplayMaxHeightInPx: Int + get() = Resources.getSystem().displayMetrics.let { max(it.heightPixels, it.widthPixels) } + /** * Converts to dp. */ @@ -258,7 +262,7 @@ fun Context.openInBrowser(uri: Uri, forceDefaultBrowser: Boolean = false) { } fun Context.defaultBrowserPackageName(): String? { - val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("http://")) + val browserIntent = Intent(Intent.ACTION_VIEW, "http://".toUri()) return packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY) ?.activityInfo?.packageName ?.takeUnless { it in DeviceUtil.invalidDefaultBrowsers } @@ -315,8 +319,8 @@ fun Context.isNightMode(): Boolean { * https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java;l=348;drc=e28752c96fc3fb4d3354781469a1af3dbded4898 */ fun Context.createReaderThemeContext(): Context { - val prefs = Injekt.get() - val isDarkBackground = when (prefs.readerTheme().get()) { + val preferences = Injekt.get() + val isDarkBackground = when (preferences.readerTheme().get()) { 1, 2 -> true // Black, Gray 3 -> applicationContext.isNightMode() // Automatic bg uses activity background by default else -> false // White @@ -329,7 +333,7 @@ fun Context.createReaderThemeContext(): Context { val wrappedContext = ContextThemeWrapper(this, R.style.Theme_Tachiyomi) wrappedContext.applyOverrideConfiguration(overrideConf) - ThemingDelegate.getThemeResIds(prefs.appTheme().get(), prefs.themeDarkAmoled().get()) + ThemingDelegate.getThemeResIds(preferences.appTheme().get(), preferences.themeDarkAmoled().get()) .forEach { wrappedContext.theme.applyStyle(it, true) } return wrappedContext } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt index 9ce75120f..3c8497d41 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt @@ -4,6 +4,7 @@ import android.content.Context import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.BitmapFactory +import android.graphics.BitmapRegionDecoder import android.graphics.Canvas import android.graphics.Color import android.graphics.Rect @@ -17,16 +18,23 @@ import androidx.core.graphics.alpha import androidx.core.graphics.applyCanvas import androidx.core.graphics.blue import androidx.core.graphics.createBitmap +import androidx.core.graphics.get import androidx.core.graphics.green import androidx.core.graphics.red +import com.hippo.unifile.UniFile +import logcat.LogPriority import tachiyomi.decoder.Format import tachiyomi.decoder.ImageDecoder +import java.io.BufferedInputStream import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream +import java.io.File +import java.io.FileOutputStream import java.io.InputStream import java.net.URLConnection import kotlin.math.abs import kotlin.math.max +import kotlin.math.min object ImageUtil { @@ -76,8 +84,7 @@ object ImageUtil { Format.Webp -> type.isAnimated && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P else -> false } - } catch (e: Exception) { - } + } catch (e: Exception) { /* Do Nothing */ } return false } @@ -109,19 +116,12 @@ object ImageUtil { } /** - * Check whether the image is a double-page spread + * Check whether the image is wide (which we consider a double-page spread). + * * @return true if the width is greater than the height */ - fun isDoublePage(imageStream: InputStream): Boolean { - imageStream.mark(imageStream.available() + 1) - - val imageBytes = imageStream.readBytes() - - val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } - BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size, options) - - imageStream.reset() - + fun isWideImage(imageStream: BufferedInputStream): Boolean { + val options = extractImageOptions(imageStream) return options.outWidth > options.outHeight } @@ -188,6 +188,111 @@ object ImageUtil { RIGHT, LEFT } + /** + * Check whether the image is considered a tall image. + * + * @return true if the height:width ratio is greater than 3. + */ + private fun isTallImage(imageStream: InputStream): Boolean { + val options = extractImageOptions(imageStream, resetAfterExtraction = false) + return (options.outHeight / options.outWidth) > 3 + } + + /** + * Splits tall images to improve performance of reader + */ + fun splitTallImage(imageFile: UniFile, imageFilePath: String): Boolean { + if (isAnimatedAndSupported(imageFile.openInputStream()) || !isTallImage(imageFile.openInputStream())) { + return true + } + + val options = extractImageOptions(imageFile.openInputStream(), resetAfterExtraction = false).apply { inJustDecodeBounds = false } + // Values are stored as they get modified during split loop + val imageHeight = options.outHeight + val imageWidth = options.outWidth + + val splitHeight = (getDisplayMaxHeightInPx * 1.5).toInt() + // -1 so it doesn't try to split when imageHeight = getDisplayHeightInPx + val partCount = (imageHeight - 1) / splitHeight + 1 + + val optimalSplitHeight = imageHeight / partCount + + val splitDataList = (0 until partCount).fold(mutableListOf()) { list, index -> + list.apply { + // Only continue if the list is empty or there is image remaining + if (isEmpty() || imageHeight > last().bottomOffset) { + val topOffset = index * optimalSplitHeight + var outputImageHeight = min(optimalSplitHeight, imageHeight - topOffset) + + val remainingHeight = imageHeight - (topOffset + outputImageHeight) + // If remaining height is smaller or equal to 1/3th of + // optimal split height then include it in current page + if (remainingHeight <= (optimalSplitHeight / 3)) { + outputImageHeight += remainingHeight + } + add(SplitData(index, topOffset, outputImageHeight)) + } + } + } + + val bitmapRegionDecoder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + BitmapRegionDecoder.newInstance(imageFile.openInputStream()) + } else { + @Suppress("DEPRECATION") + BitmapRegionDecoder.newInstance(imageFile.openInputStream(), false) + } + + if (bitmapRegionDecoder == null) { + logcat { "Failed to create new instance of BitmapRegionDecoder" } + return false + } + + logcat { + "Splitting image with height of $imageHeight into $partCount part " + + "with estimated ${optimalSplitHeight}px height per split" + } + + return try { + splitDataList.forEach { splitData -> + val splitPath = splitImagePath(imageFilePath, splitData.index) + + val region = Rect(0, splitData.topOffset, imageWidth, splitData.bottomOffset) + + FileOutputStream(splitPath).use { outputStream -> + val splitBitmap = bitmapRegionDecoder.decodeRegion(region, options) + splitBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) + splitBitmap.recycle() + } + logcat { + "Success: Split #${splitData.index + 1} with topOffset=${splitData.topOffset} " + + "height=${splitData.outputImageHeight} bottomOffset=${splitData.bottomOffset}" + } + } + imageFile.delete() + true + } catch (e: Exception) { + // Image splits were not successfully saved so delete them and keep the original image + splitDataList + .map { splitImagePath(imageFilePath, it.index) } + .forEach { File(it).delete() } + logcat(LogPriority.ERROR, e) + false + } finally { + bitmapRegionDecoder.recycle() + } + } + + private fun splitImagePath(imageFilePath: String, index: Int) = + imageFilePath.substringBeforeLast(".") + "__${"%03d".format(index + 1)}.jpg" + + data class SplitData( + val index: Int, + val topOffset: Int, + val outputImageHeight: Int, + ) { + val bottomOffset = topOffset + outputImageHeight + } + /** * Algorithm for determining what background to accompany a comic/manga page */ @@ -212,14 +317,14 @@ object ImageUtil { val leftOffsetX = left - offsetX val rightOffsetX = right + offsetX - val topLeftPixel = image.getPixel(left, top) - val topRightPixel = image.getPixel(right, top) - val midLeftPixel = image.getPixel(left, midY) - val midRightPixel = image.getPixel(right, midY) - val topCenterPixel = image.getPixel(midX, top) - val botLeftPixel = image.getPixel(left, bot) - val bottomCenterPixel = image.getPixel(midX, bot) - val botRightPixel = image.getPixel(right, bot) + val topLeftPixel = image[left, top] + val topRightPixel = image[right, top] + val midLeftPixel = image[left, midY] + val midRightPixel = image[right, midY] + val topCenterPixel = image[midX, top] + val botLeftPixel = image[left, bot] + val bottomCenterPixel = image[midX, bot] + val botRightPixel = image[right, bot] val topLeftIsDark = topLeftPixel.isDark() val topRightIsDark = topRightPixel.isDark() @@ -272,8 +377,8 @@ object ImageUtil { var whiteStreak = false val notOffset = x == left || x == right inner@ for ((index, y) in (0 until image.height step image.height / 25).withIndex()) { - val pixel = image.getPixel(x, y) - val pixelOff = image.getPixel(x + (if (x < image.width / 2) -offsetX else offsetX), y) + val pixel = image[x, y] + val pixelOff = image[x + (if (x < image.width / 2) -offsetX else offsetX), y] if (pixel.isWhite()) { whitePixelsStreak++ whitePixels++ @@ -364,8 +469,8 @@ object ImageUtil { val topCornersIsDark = topLeftIsDark && topRightIsDark val botCornersIsDark = botLeftIsDark && botRightIsDark - val topOffsetCornersIsDark = image.getPixel(leftOffsetX, top).isDark() && image.getPixel(rightOffsetX, top).isDark() - val botOffsetCornersIsDark = image.getPixel(leftOffsetX, bot).isDark() && image.getPixel(rightOffsetX, bot).isDark() + val topOffsetCornersIsDark = image[leftOffsetX, top].isDark() && image[rightOffsetX, top].isDark() + val botOffsetCornersIsDark = image[leftOffsetX, bot].isDark() && image[rightOffsetX, bot].isDark() val gradient = when { darkBG && botCornersIsWhite -> { @@ -394,15 +499,31 @@ object ImageUtil { ) } - private fun Int.isDark(): Boolean = + private fun @receiver:ColorInt Int.isDark(): Boolean = red < 40 && blue < 40 && green < 40 && alpha > 200 - private fun Int.isCloseTo(other: Int): Boolean = + private fun @receiver:ColorInt Int.isCloseTo(other: Int): Boolean = abs(red - other.red) < 30 && abs(green - other.green) < 30 && abs(blue - other.blue) < 30 - private fun Int.isWhite(): Boolean = + private fun @receiver:ColorInt Int.isWhite(): Boolean = red + blue + green > 740 + /** + * Used to check an image's dimensions without loading it in the memory. + */ + private fun extractImageOptions( + imageStream: InputStream, + resetAfterExtraction: Boolean = true, + ): BitmapFactory.Options { + imageStream.mark(imageStream.available() + 1) + + val imageBytes = imageStream.readBytes() + val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } + BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size, options) + if (resetAfterExtraction) imageStream.reset() + return options + } + // Android doesn't include some mappings private val SUPPLEMENTARY_MIMETYPE_MAPPING = mapOf( // https://issuetracker.google.com/issues/182703810 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f80edb54b..6fd6789d1 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -410,6 +410,8 @@ Download new chapters Manga in excluded categories will not be downloaded even if they are also in included categories. Save as CBZ archive + Auto split tall images + Improves reader performance by splitting tall downloaded images. Tracking guide @@ -810,6 +812,9 @@ No network connection available Download paused Download completed + Page %d not found while splitting + Couldn\'t find file path of page %d + Couldn\'t split downloaded image Common From 85bd12e731dfe4e694328007a7ea610c1c317d28 Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 10 Jun 2022 09:49:50 -0400 Subject: [PATCH 22/34] Actually compare chapter numbers as numbers when sorting (fixes #7247) (cherry picked from commit da8669c826e6575a76751842bda3da59dc2f07c7) (cherry picked from commit 4b7b710b7cc2e3526de176eb0eb72d763b32bcd7) # Conflicts: # app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt --- .../tachiyomi/util/chapter/ChapterSorter.kt | 7 +++---- .../util/chapter/ChapterRecognitionTest.kt | 17 ++--------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSorter.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSorter.kt index 764f00491..a069a2c7c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSorter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSorter.kt @@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.util.chapter import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder fun getChapterSort(manga: Manga, sortDescending: Boolean = manga.sortDescending()): (Chapter, Chapter) -> Int { return when (manga.sorting) { @@ -11,13 +10,13 @@ fun getChapterSort(manga: Manga, sortDescending: Boolean = manga.sortDescending( false -> { c1, c2 -> c2.source_order.compareTo(c1.source_order) } } Manga.CHAPTER_SORTING_NUMBER -> when (sortDescending) { - true -> { c1, c2 -> c2.chapter_number.toString().compareToCaseInsensitiveNaturalOrder(c1.chapter_number.toString()) } - false -> { c1, c2 -> c1.chapter_number.toString().compareToCaseInsensitiveNaturalOrder(c2.chapter_number.toString()) } + true -> { c1, c2 -> c2.chapter_number.compareTo(c1.chapter_number) } + false -> { c1, c2 -> c1.chapter_number.compareTo(c2.chapter_number) } } Manga.CHAPTER_SORTING_UPLOAD_DATE -> when (sortDescending) { true -> { c1, c2 -> c2.date_upload.compareTo(c1.date_upload) } false -> { c1, c2 -> c1.date_upload.compareTo(c2.date_upload) } } - else -> throw NotImplementedError("Unimplemented sorting method") + else -> throw NotImplementedError("Invalid chapter sorting method: ${manga.sorting}") } } diff --git a/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt b/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt index 1887ff4da..bf99f171a 100644 --- a/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt +++ b/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt @@ -256,20 +256,7 @@ class ChapterRecognitionTest { } private fun assertChapter(mangaTitle: String, name: String, expected: Float) { - val chapter = createChapter(name) - ChapterRecognition.parseChapterNumber(chapter, createManga(mangaTitle)) - assertEquals(expected, chapter.chapter_number) - } - - private fun createManga(title: String): Manga { - val manga = Manga.create(0) - manga.title = title - return manga - } - - private fun createChapter(name: String): Chapter { - val chapter = Chapter.create() - chapter.name = name - return chapter + val chapterNumber = parseChapterNumber(mangaTitle, name) + assertEquals(chapterNumber, expected) } } From 5d5678861df0a87fbebfd51b48f96c06257deaa3 Mon Sep 17 00:00:00 2001 From: nicki <72807749+curche@users.noreply.github.com> Date: Sun, 12 Jun 2022 19:54:39 +0530 Subject: [PATCH 23/34] Fix Links to Changelog/Readme/Commits for `multisrc` (#7252) * Fix Links to Changelog/Readme/Commits for `multisrc` working basic fix. Needs to be refactored into `createUrl()` * Refactor back into `createUrl` hopefully the logic is understandable there's three cases: - when multisrc, if `path` isn't mentioned, then we're trying to open commmit history - when multisrc, if `path` is mentioned, then its either a changelog or a readme to a multisrc extension, the files are stored in the `overrides` subfolder - when not multisrc, we're looking at a single source where the links are constructed in the same way regardless of it being changelog/readme/commit history (cherry picked from commit e7695aef78c92c10e5bae953b24a19e67ac156af) (cherry picked from commit 25e007504188463b6e11f1a8b85d2990afef6e75) --- .../extension/details/ExtensionDetailsController.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsController.kt index 7d76967e1..c80f1a9d4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsController.kt @@ -247,9 +247,13 @@ class ExtensionDetailsController(bundle: Bundle? = null) : } private fun createUrl(url: String, pkgName: String, pkgFactory: String?, path: String = ""): String { - return when { - !pkgFactory.isNullOrEmpty() -> "$url/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/$pkgFactory$path" - else -> "$url/src/${pkgName.replace(".", "/")}$path" + return if (!pkgFactory.isNullOrEmpty()) { + when (path.isEmpty()) { + true -> "$url/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/$pkgFactory" + else -> "$url/multisrc/overrides/$pkgFactory/" + (pkgName.split(".").lastOrNull() ?: "") + path + } + } else { + url + "/src/" + pkgName.replace(".", "/") + path } } From 5dcdd3454b1bf08f3e7c662faf959dfb579c1f96 Mon Sep 17 00:00:00 2001 From: CVIUS <84634607+CVIUS@users.noreply.github.com> Date: Thu, 12 May 2022 20:58:37 +0800 Subject: [PATCH 24/34] Detect identical mangas when long pressing to add to library (#7095) * Detect identical mangas when long pressing to add to library * Use extracted duplicate manga dialog to avoid duplication * Partially revert previous commit * Review changes * Review changes part 2 (cherry picked from commit f1afeac0bcd3904c323e24d67dd945c85c666f92) (cherry picked from commit afd1c3b49155e68011f24593a2663c285d6c4e66) --- .../source/browse/BrowseSourceController.kt | 74 +++++++++++-------- .../source/browse/BrowseSourcePresenter.kt | 4 + 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt index 488cb6689..534779c2b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt @@ -41,6 +41,7 @@ import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting import eu.kanade.tachiyomi.ui.main.MainActivity +import eu.kanade.tachiyomi.ui.manga.AddDuplicateMangaDialog import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.more.MoreController import eu.kanade.tachiyomi.ui.webview.WebViewActivity @@ -742,6 +743,7 @@ open class BrowseSourceController(bundle: Bundle) : override fun onItemLongClick(position: Int) { val activity = activity ?: return val manga = (adapter?.getItem(position) as? SourceItem?)?.manga ?: return + val duplicateManga = presenter.getDuplicateLibraryManga(manga) if (manga.favorite) { MaterialAlertDialogBuilder(activity) @@ -757,43 +759,53 @@ open class BrowseSourceController(bundle: Bundle) : } .show() } else { - val categories = presenter.getCategories() - val defaultCategoryId = preferences.defaultCategory() - val defaultCategory = categories.find { it.id == defaultCategoryId } + if (duplicateManga != null) { + AddDuplicateMangaDialog(this, duplicateManga) { addToLibrary(manga, position) } + .showDialog(router) + } else { + addToLibrary(manga, position) + } + } + } - when { - // Default category set - defaultCategory != null -> { - presenter.moveMangaToCategory(manga, defaultCategory) + private fun addToLibrary(newManga: Manga, position: Int) { + val activity = activity ?: return + val categories = presenter.getCategories() + val defaultCategoryId = preferences.defaultCategory() + val defaultCategory = categories.find { it.id == defaultCategoryId } - presenter.changeMangaFavorite(manga) - adapter?.notifyItemChanged(position) - activity.toast(activity.getString(R.string.manga_added_library)) - } + when { + // Default category set + defaultCategory != null -> { + presenter.moveMangaToCategory(newManga, defaultCategory) - // Automatic 'Default' or no categories - defaultCategoryId == 0 || categories.isEmpty() -> { - presenter.moveMangaToCategory(manga, null) + presenter.changeMangaFavorite(newManga) + adapter?.notifyItemChanged(position) + activity.toast(activity.getString(R.string.manga_added_library)) + } - presenter.changeMangaFavorite(manga) - adapter?.notifyItemChanged(position) - activity.toast(activity.getString(R.string.manga_added_library)) - } + // Automatic 'Default' or no categories + defaultCategoryId == 0 || categories.isEmpty() -> { + presenter.moveMangaToCategory(newManga, null) - // Choose a category - else -> { - val ids = presenter.getMangaCategoryIds(manga) - val preselected = categories.map { - if (it.id in ids) { - QuadStateTextView.State.CHECKED.ordinal - } else { - QuadStateTextView.State.UNCHECKED.ordinal - } - }.toTypedArray() + presenter.changeMangaFavorite(newManga) + adapter?.notifyItemChanged(position) + activity.toast(activity.getString(R.string.manga_added_library)) + } - ChangeMangaCategoriesDialog(this, listOf(manga), categories, preselected) - .showDialog(router) - } + // Choose a category + else -> { + val ids = presenter.getMangaCategoryIds(newManga) + val preselected = categories.map { + if (it.id in ids) { + QuadStateTextView.State.CHECKED.ordinal + } else { + QuadStateTextView.State.UNCHECKED.ordinal + } + }.toTypedArray() + + ChangeMangaCategoriesDialog(this, listOf(newManga), categories, preselected) + .showDialog(router) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt index b0759389e..89f0b2c0f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt @@ -435,6 +435,10 @@ open class BrowseSourcePresenter( return db.getCategories().executeAsBlocking() } + fun getDuplicateLibraryManga(manga: Manga): Manga? { + return db.getDuplicateLibraryManga(manga).executeAsBlocking() + } + /** * Gets the category id's the manga is in, if the manga is not in a category, returns the default id. * From 048587468d64c31baadfba92abc1d3603234fb06 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 7 May 2022 11:04:55 -0400 Subject: [PATCH 25/34] Don't allow swiping away app update install notification Also show the new version number in the notifications. (cherry picked from commit 4aa5c6107ca28bde042095b53f6639aa4444c977) --- .../eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt | 2 ++ .../eu/kanade/tachiyomi/data/updater/AppUpdateService.kt | 2 +- .../eu/kanade/tachiyomi/ui/more/NewUpdateDialogController.kt | 5 ++++- app/src/main/res/values/strings.xml | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt index 242835f38..8d13b8928 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt @@ -29,6 +29,7 @@ internal class AppUpdateNotifier(private val context: Context) { fun promptUpdate(release: GithubRelease) { val intent = Intent(context, AppUpdateService::class.java).apply { putExtra(AppUpdateService.EXTRA_DOWNLOAD_URL, release.getDownloadLink()) + putExtra(AppUpdateService.EXTRA_DOWNLOAD_TITLE, release.version) } val updateIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) @@ -116,6 +117,7 @@ internal class AppUpdateNotifier(private val context: Context) { setOnlyAlertOnce(false) setProgress(0, 0, false) setContentIntent(installIntent) + setOngoing(true) clearActions() addAction( diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt index 470151116..5a8808fcc 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt @@ -147,7 +147,7 @@ class AppUpdateService : Service() { * @param context the application context. * @param url the url to the new update. */ - fun start(context: Context, url: String, title: String = context.getString(R.string.app_name)) { + fun start(context: Context, url: String, title: String? = context.getString(R.string.app_name)) { if (!isRunning(context)) { val intent = Intent(context, AppUpdateService::class.java).apply { putExtra(EXTRA_DOWNLOAD_TITLE, title) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/NewUpdateDialogController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/NewUpdateDialogController.kt index 01053d5de..b7bca75a7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/NewUpdateDialogController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/NewUpdateDialogController.kt @@ -19,6 +19,7 @@ class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundl constructor(update: AppUpdateResult.NewUpdate) : this( bundleOf( BODY_KEY to update.release.info, + VERSION_KEY to update.release.version, RELEASE_URL_KEY to update.release.releaseLink, DOWNLOAD_URL_KEY to update.release.getDownloadLink(), ), @@ -36,7 +37,8 @@ class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundl applicationContext?.let { context -> // Start download val url = args.getString(DOWNLOAD_URL_KEY)!! - AppUpdateService.start(context, url) + val version = args.getString(VERSION_KEY) + AppUpdateService.start(context, url, version) } } .setNeutralButton(R.string.update_check_open) { _, _ -> @@ -55,5 +57,6 @@ class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundl } private const val BODY_KEY = "NewUpdateDialogController.body" +private const val VERSION_KEY = "NewUpdateDialogController.version" private const val RELEASE_URL_KEY = "NewUpdateDialogController.release_url" private const val DOWNLOAD_URL_KEY = "NewUpdateDialogController.download_url" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6fd6789d1..71f90d2b8 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -775,7 +775,7 @@ Downloading… - Download complete + Tap to install Download error New version available! A new version is available from the official releases. Tap to learn how to migrate from unofficial F-Droid releases. From d09de07a3fdaec8ef6eab0582c8c89c882e44ed2 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 9 Jul 2022 00:00:18 -0400 Subject: [PATCH 26/34] Cleanup --- .../ui/browse/extension/details/ExtensionDetailsController.kt | 2 +- app/src/main/res/layout/pref_settings.xml | 2 +- .../eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt | 2 -- gradle/libs.versions.toml | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsController.kt index c80f1a9d4..d0634cda6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsController.kt @@ -253,7 +253,7 @@ class ExtensionDetailsController(bundle: Bundle? = null) : else -> "$url/multisrc/overrides/$pkgFactory/" + (pkgName.split(".").lastOrNull() ?: "") + path } } else { - url + "/src/" + pkgName.replace(".", "/") + path + url + "/src/" + pkgName.replace(".", "/") + path } } diff --git a/app/src/main/res/layout/pref_settings.xml b/app/src/main/res/layout/pref_settings.xml index a4b6f6eba..413139331 100644 --- a/app/src/main/res/layout/pref_settings.xml +++ b/app/src/main/res/layout/pref_settings.xml @@ -17,7 +17,7 @@ app:tint="?attr/colorOnBackground" /> - diff --git a/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt b/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt index bf99f171a..b94f1aee8 100644 --- a/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt +++ b/app/src/test/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognitionTest.kt @@ -1,7 +1,5 @@ package eu.kanade.tachiyomi.util.chapter -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.Manga import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.parallel.Execution diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0e1b8a7a2..baa29f915 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,7 +57,7 @@ natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1" markwon = "io.noties.markwon:core:4.6.2" -material = "com.google.android.material:material:1.7.0-alpha01" +material = "com.google.android.material:material:1.7.0-alpha02" androidprocessbutton = "com.github.dmytrodanylyk.android-process-button:library:1.0.4" flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013533" flexible-adapter-ui = "com.github.arkon.FlexibleAdapter:flexible-adapter-ui:c8013533" From 2b9d564841029d902c0fdbcc1824f470417d027a Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Tue, 26 Jul 2022 16:30:51 -0400 Subject: [PATCH 27/34] Minor improvements for delegated source id lists (cherry picked from commit 1d593de65440ddb531ee0421d17c6033a52dd5bb) --- .../kanade/tachiyomi/source/SourceManager.kt | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt index ff357aa1c..31c15eb61 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt @@ -253,7 +253,7 @@ open class SourceManager(private val context: Context) { ), ).associateBy { it.originalSourceQualifiedClassName } - val currentDelegatedSources = ListenMutableMap(mutableMapOf(), ::handleSourceLibrary) + val currentDelegatedSources: MutableMap = ListenMutableMap(mutableMapOf(), ::handleSourceLibrary) data class DelegatedSource( val sourceName: String, @@ -264,19 +264,10 @@ open class SourceManager(private val context: Context) { ) } - class ListenMutableMap(private val internalMap: MutableMap, val listener: () -> Unit) : MutableMap { - override val size: Int - get() = internalMap.size - override fun containsKey(key: K): Boolean = internalMap.containsKey(key) - override fun containsValue(value: V): Boolean = internalMap.containsValue(value) - override fun get(key: K): V? = internalMap[key] - override fun isEmpty(): Boolean = internalMap.isEmpty() - override val entries: MutableSet> - get() = internalMap.entries - override val keys: MutableSet - get() = internalMap.keys - override val values: MutableCollection - get() = internalMap.values + private class ListenMutableMap( + private val internalMap: MutableMap, + private val listener: () -> Unit, + ) : MutableMap by internalMap { override fun clear() { val clearResult = internalMap.clear() listener() From af070a3f0a516456fe3815b09ba099b34ff4bcc7 Mon Sep 17 00:00:00 2001 From: CVIUS <84634607+CVIUS@users.noreply.github.com> Date: Thu, 12 May 2022 20:58:37 +0800 Subject: [PATCH 28/34] Detect identical mangas when long pressing to add to library (#7095) * Detect identical mangas when long pressing to add to library * Use extracted duplicate manga dialog to avoid duplication * Partially revert previous commit * Review changes * Review changes part 2 (cherry picked from commit f1afeac0bcd3904c323e24d67dd945c85c666f92) (cherry picked from commit 431c04e54f4acd1c660e83c27886c38955b67871) --- .../ui/manga/AddDuplicateMangaDialog.kt | 48 +++++++++++++++++++ .../tachiyomi/ui/manga/MangaController.kt | 15 +----- 2 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/manga/AddDuplicateMangaDialog.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/AddDuplicateMangaDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/AddDuplicateMangaDialog.kt new file mode 100644 index 000000000..8cac9c030 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/AddDuplicateMangaDialog.kt @@ -0,0 +1,48 @@ +package eu.kanade.tachiyomi.ui.manga + +import android.app.Dialog +import android.os.Bundle +import com.bluelinelabs.conductor.Controller +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.ui.base.controller.DialogController +import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction +import uy.kohesive.injekt.injectLazy + +class AddDuplicateMangaDialog(bundle: Bundle? = null) : DialogController(bundle) { + + private val sourceManager: SourceManager by injectLazy() + + private lateinit var libraryManga: Manga + private lateinit var onAddToLibrary: () -> Unit + + constructor( + target: Controller, + libraryManga: Manga, + onAddToLibrary: () -> Unit, + ) : this() { + targetController = target + + this.libraryManga = libraryManga + this.onAddToLibrary = onAddToLibrary + } + + override fun onCreateDialog(savedViewState: Bundle?): Dialog { + val source = sourceManager.getOrStub(libraryManga.source) + + return MaterialAlertDialogBuilder(activity!!) + .setMessage(activity?.getString(R.string.confirm_manga_add_duplicate, source.name)) + .setPositiveButton(activity?.getString(R.string.action_add)) { _, _ -> + onAddToLibrary() + } + .setNegativeButton(android.R.string.cancel, null) + .setNeutralButton(activity?.getString(R.string.action_show_manga)) { _, _ -> + dismissDialog() + router.pushController(MangaController(libraryManga.id!!).withFadeTransaction()) + } + .setCancelable(true) + .create() + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index f43e8073e..bdf96abd7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -29,7 +29,6 @@ import coil.request.ImageRequest import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeType -import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.snackbar.Snackbar import dev.chrisbanes.insetter.applyInsetter @@ -673,18 +672,8 @@ class MangaController : private fun showAddDuplicateDialog(newManga: Manga, libraryManga: Manga) { activity?.let { - val source = sourceManager.getOrStub(libraryManga.source) - MaterialAlertDialogBuilder(it).apply { - setMessage(activity?.getString(R.string.confirm_manga_add_duplicate, source.name)) - setPositiveButton(activity?.getString(R.string.action_add)) { _, _ -> - addToLibrary(newManga) - } - setNegativeButton(activity?.getString(R.string.action_cancel)) { _, _ -> } - setNeutralButton(activity?.getString(R.string.action_show_manga)) { _, _ -> - router.pushController(MangaController(libraryManga).withFadeTransaction()) - } - setCancelable(true) - }.create().show() + AddDuplicateMangaDialog(this, libraryManga) { addToLibrary(newManga) } + .showDialog(router) } } From 655126eaa2f26562c3b0ee0810ebe43e75a66cc8 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Sat, 13 Aug 2022 15:46:27 -0400 Subject: [PATCH 29/34] Fixes --- .../advanced/process/MigrationListController.kt | 4 ++-- .../ui/reader/viewer/ReaderTransitionView.kt | 12 ++++-------- app/src/main/java/exh/EXHMigrations.kt | 7 ++++--- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListController.kt index e8250df0b..5d013128b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListController.kt @@ -474,8 +474,8 @@ class MigrationListController(bundle: Bundle? = null) : } private fun MenuItem.setIconTint(enabled: Boolean, color: Int) { - icon.mutate() - icon.setTint(color) + icon?.mutate() + icon?.setTint(color) isEnabled = enabled } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt index c46a1fa9c..bdd6712bf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt @@ -53,10 +53,8 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At if (prevChapter != null) { binding.upperText.textAlignment = TEXT_ALIGNMENT_TEXT_START val isPrevDownloaded = downloadManager.isChapterDownloaded( - prevChapter.name, - prevChapter.scanlator, - manga.title, - manga.source, + prevChapter, + manga ) val isCurrentDownloaded = transition.from.pageLoader is DownloadPageLoader binding.upperText.text = buildSpannedString { @@ -90,10 +88,8 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At binding.upperText.textAlignment = TEXT_ALIGNMENT_TEXT_START val isCurrentDownloaded = transition.from.pageLoader is DownloadPageLoader val isNextDownloaded = downloadManager.isChapterDownloaded( - nextChapter.name, - nextChapter.scanlator, - manga.title, - manga.source, + nextChapter, + manga ) binding.upperText.text = buildSpannedString { bold { append(context.getString(R.string.transition_finished)) } diff --git a/app/src/main/java/exh/EXHMigrations.kt b/app/src/main/java/exh/EXHMigrations.kt index fcf49c066..fcdeca203 100644 --- a/app/src/main/java/exh/EXHMigrations.kt +++ b/app/src/main/java/exh/EXHMigrations.kt @@ -37,6 +37,7 @@ import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.util.preference.minusAssign import eu.kanade.tachiyomi.util.system.DeviceUtil +import eu.kanade.tachiyomi.util.system.logcat import exh.eh.EHentaiUpdateWorker import exh.log.xLogE import exh.log.xLogW @@ -314,14 +315,14 @@ object EXHMigrations { val newSortingMode = when (oldSortingMode) { 0 -> SortModeSetting.ALPHABETICAL 1 -> SortModeSetting.LAST_READ - 2 -> SortModeSetting.LAST_MANGA_UPDATE - 3 -> SortModeSetting.UNREAD_COUNT + 2 -> SortModeSetting.LAST_CHECKED + 3 -> SortModeSetting.UNREAD 4 -> SortModeSetting.TOTAL_CHAPTERS 6 -> SortModeSetting.LATEST_CHAPTER 7 -> SortModeSetting.DRAG_AND_DROP 8 -> SortModeSetting.DATE_ADDED 9 -> SortModeSetting.TAG_LIST - 10 -> SortModeSetting.CHAPTER_FETCH_DATE + 10 -> SortModeSetting.DATE_FETCHED else -> SortModeSetting.ALPHABETICAL } From a08e4e616d1f0b1d0cdcd80b0a2f9bacf096e704 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Fri, 5 Aug 2022 16:34:00 -0400 Subject: [PATCH 30/34] Update EHTags list (cherry picked from commit 05f2f79e0dee56220951ff19c0c0e4ac6d735f3d) --- .../tachiyomi/source/online/all/EHentai.kt | 4 +- app/src/main/java/exh/eh/EHTags.kt | 11 +- app/src/main/java/exh/eh/tags/Artist.kt | 335 +++++++------- app/src/main/java/exh/eh/tags/Artist2.kt | 322 +++++++++++++- app/src/main/java/exh/eh/tags/Character.kt | 183 +++++++- app/src/main/java/exh/eh/tags/Cosplayer.kt | 79 +++- app/src/main/java/exh/eh/tags/Female.kt | 77 +++- app/src/main/java/exh/eh/tags/Group.kt | 415 +++--------------- app/src/main/java/exh/eh/tags/Group2.kt | 342 +++++++++++++++ app/src/main/java/exh/eh/tags/Language.kt | 2 +- app/src/main/java/exh/eh/tags/Male.kt | 138 +++++- app/src/main/java/exh/eh/tags/Mixed.kt | 4 +- app/src/main/java/exh/eh/tags/Other.kt | 8 +- app/src/main/java/exh/eh/tags/Parody.kt | 75 +++- .../exh/eh/tags/{ReClass.kt => Reclass.kt} | 5 +- app/src/main/java/exh/eh/tags/TagList.kt | 5 +- 16 files changed, 1436 insertions(+), 569 deletions(-) create mode 100644 app/src/main/java/exh/eh/tags/Group2.kt rename app/src/main/java/exh/eh/tags/{ReClass.kt => Reclass.kt} (78%) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt index 9a5ff17f6..0a060de3b 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt @@ -835,8 +835,8 @@ class EHentai( ) }, AutoCompleteTags( - EHTags.getNamespaces0Tags().map { "$it:" } + EHTags.getAllTags(), - EHTags.getNamespaces0Tags().map { "$it:" }, + EHTags.getNamespaces().map { "$it:" } + EHTags.getAllTags(), + EHTags.getNamespaces().map { "$it:" }, excludePrefix, ), if (preferences.exhWatchedListDefaultState().get()) { diff --git a/app/src/main/java/exh/eh/EHTags.kt b/app/src/main/java/exh/eh/EHTags.kt index dbc777d7f..310c6fb55 100644 --- a/app/src/main/java/exh/eh/EHTags.kt +++ b/app/src/main/java/exh/eh/EHTags.kt @@ -6,31 +6,32 @@ import exh.eh.tags.Character import exh.eh.tags.Cosplayer import exh.eh.tags.Female import exh.eh.tags.Group +import exh.eh.tags.Group2 import exh.eh.tags.Language import exh.eh.tags.Male import exh.eh.tags.Mixed import exh.eh.tags.Other import exh.eh.tags.Parody -import exh.eh.tags.ReClass +import exh.eh.tags.Reclass object EHTags { - - fun getAllTags() = listOf( + fun getAllTags(): List = listOf( Female.getTags(), Male.getTags(), Language.getTags(), - ReClass.getTags(), + Reclass.getTags(), Mixed.getTags(), Other.getTags(), Cosplayer.getTags(), Parody.getTags(), Character.getTags(), Group.getTags(), + Group2.getTags(), Artist.getTags(), Artist2.getTags(), ).flatten().flatten() - fun getNamespaces0Tags() = listOf( + fun getNamespaces(): List = listOf( "reclass", "language", "parody", diff --git a/app/src/main/java/exh/eh/tags/Artist.kt b/app/src/main/java/exh/eh/tags/Artist.kt index 2406aba94..a7b7aead2 100644 --- a/app/src/main/java/exh/eh/tags/Artist.kt +++ b/app/src/main/java/exh/eh/tags/Artist.kt @@ -1,14 +1,15 @@ package exh.eh.tags object Artist : TagList { - - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( "artist:-helic-", "artist:.357-inch", "artist:.less", "artist:007", + "artist:03", "artist:0rang3", "artist:0uka", + "artist:0w0wer", "artist:1 equals 2", "artist:1 tsu o", "artist:1-gou", @@ -48,7 +49,9 @@ object Artist : TagList { "artist:33297", "artist:348", "artist:34san", + "artist:35 machi", "artist:360", + "artist:38", "artist:39rou", "artist:3dcaptor", "artist:3e", @@ -94,8 +97,10 @@ object Artist : TagList { "artist:a.s. hermes", "artist:a.sou", "artist:a1", + "artist:a20", "artist:a5w", "artist:a6", + "artist:aa", "artist:aaa", "artist:aapon", "artist:aaron", @@ -135,12 +140,14 @@ object Artist : TagList { "artist:achumuchi", "artist:acid-lsd", "artist:acidapluvia", + "artist:acrobatic-sala", "artist:adachi cloud", "artist:adachi himiko", "artist:adachi ken", "artist:adachi kizoku", "artist:adachi mitsuru", "artist:adachi takumi", + "artist:adam ellis", "artist:adam wan", "artist:addis abeba", "artist:addyredragon", @@ -174,11 +181,13 @@ object Artist : TagList { "artist:agemo agm", "artist:agemon", "artist:agent red girl", + "artist:agent ss", "artist:agent tygress", "artist:aggro badger", "artist:agitype", "artist:agm", "artist:agroantirrhopus", + "artist:aguni-yunta", "artist:agurecchi", "artist:ahashima", "artist:ahcuna k bartista", @@ -195,6 +204,7 @@ object Artist : TagList { "artist:aida ruki", "artist:aida yu", "artist:aidans", + "artist:aihara", "artist:aihara shouta", "artist:aikawa ruru", "artist:aikawa ryou", @@ -303,6 +313,7 @@ object Artist : TagList { "artist:akikusa peperon", "artist:akimori akira", "artist:akimoto karma", + "artist:akimoto nigou", "artist:akimoto osamu", "artist:akimoto ryo", "artist:akinaie", @@ -395,6 +406,7 @@ object Artist : TagList { "artist:alfonso azpiri", "artist:alfort", "artist:alfre-tori", + "artist:alfredo pons rubio", "artist:alicecrazy", "artist:alicegawa chisato", "artist:alien1452", @@ -410,6 +422,7 @@ object Artist : TagList { "artist:alonzis dryke", "artist:alorok", "artist:alpha alf layla", + "artist:alphabravo", "artist:alpine", "artist:altereggo", "artist:alterinku", @@ -447,6 +460,7 @@ object Artist : TagList { "artist:amanatsu mero", "artist:amanda conner", "artist:amane hasuhito", + "artist:amane hayabusa", "artist:amane hiwo", "artist:amane toumei-do", "artist:amano ameno", @@ -635,6 +649,7 @@ object Artist : TagList { "artist:aono keita", "artist:aono rokugou", "artist:aono3", + "artist:aonosuke", "artist:aotsu umihito", "artist:aoume kaito", "artist:aox", @@ -648,6 +663,7 @@ object Artist : TagList { "artist:apart", "artist:apeiron-macro", "artist:aper", + "artist:aphrodos", "artist:apocalypse 3dx", "artist:apri", "artist:apulaz", @@ -727,6 +743,7 @@ object Artist : TagList { "artist:arne cooper", "artist:arno", "artist:aro hiroshi", + "artist:aro usagi", "artist:arobiro", "artist:arofa tamahn", "artist:aroma sensei", @@ -751,6 +768,7 @@ object Artist : TagList { "artist:aru tera", "artist:aruginin", "artist:arukime desu", + "artist:arukuno troy", "artist:arumamai ayuka plus", "artist:aruman", "artist:aruto naruto", @@ -798,6 +816,7 @@ object Artist : TagList { "artist:ashely", "artist:ashibi", "artist:ashimoto yoika", + "artist:ashina mellow", "artist:ashinano hitoshi", "artist:ashiomi masato", "artist:ashisyun", @@ -814,6 +833,7 @@ object Artist : TagList { "artist:assley", "artist:astarael abhorsen", "artist:aster crowley", + "artist:astraea-r", "artist:astroguy2", "artist:asuka yumiki", "artist:asuka111", @@ -824,6 +844,7 @@ object Artist : TagList { "artist:at2.", "artist:ataka atsushi", "artist:atamae", + "artist:atamajakusha", "artist:atari hiroyuki", "artist:atari-mitsuku", "artist:atatata-p", @@ -910,6 +931,7 @@ object Artist : TagList { "artist:azuma tesshin", "artist:azuma yuki", "artist:azumamituki", + "artist:azumaya manju", "artist:azumi amane", "artist:azumi asami", "artist:azumi tohru", @@ -946,6 +968,7 @@ object Artist : TagList { "artist:bajinappo", "artist:bajou takurou", "artist:bak hyeong jun", + "artist:bakemonoy", "artist:bakerboi", "artist:baku p", "artist:balakir", @@ -969,6 +992,7 @@ object Artist : TagList { "artist:barascrawls", "artist:barasui", "artist:barbara canepa", + "artist:barbarian takamoto", "artist:bard", "artist:bareisho", "artist:barlun", @@ -981,6 +1005,7 @@ object Artist : TagList { "artist:basnip", "artist:bastien vives", "artist:basuke", + "artist:basyosyo", "artist:batako", "artist:bathgate21", "artist:battle franky", @@ -1010,11 +1035,13 @@ object Artist : TagList { "artist:belka dog", "artist:bellendviii", "artist:bellsuke", + "artist:bellum", "artist:bemannen", "artist:ben 10mil", "artist:ben987", "artist:bendzz", "artist:benhxgx", + "artist:beniamino delvecchio", "artist:benico", "artist:benishouga", "artist:benisuzume", @@ -1086,6 +1113,7 @@ object Artist : TagList { "artist:blackwhiplash", "artist:blacnovasfm", "artist:blakknight08", + "artist:blanclauz", "artist:blargsnarf", "artist:bleedingpervert", "artist:blink3r", @@ -1094,6 +1122,7 @@ object Artist : TagList { "artist:blondevelvet", "artist:blood asp", "artist:bloomer hogero", + "artist:blox", "artist:blu3danny", "artist:bludraconoid", "artist:blue gk", @@ -1129,6 +1158,7 @@ object Artist : TagList { "artist:bon curry", "artist:bon-3000", "artist:bonaparte gohan", + "artist:bonerbob", "artist:bones", "artist:bonnie", "artist:bonriki honten", @@ -1140,9 +1170,12 @@ object Artist : TagList { "artist:boobsterprime", "artist:boogsburr", "artist:bookmoun10", + "artist:boole", + "artist:boon", "artist:bootyelectric", "artist:borba", "artist:bored user", + "artist:boris alien", "artist:borisu", "artist:born-to-die", "artist:borscht", @@ -1176,6 +1209,7 @@ object Artist : TagList { "artist:bronxden", "artist:brother pierrot", "artist:brother-tico", + "artist:brulee", "artist:bruno coq", "artist:bruno di sano", "artist:bruno diaz", @@ -1192,6 +1226,7 @@ object Artist : TagList { "artist:bunapi 397 yen", "artist:burbur", "artist:buredo", + "artist:burgers n shakes", "artist:buriburi gakko", "artist:buriteri", "artist:burst 1", @@ -1239,8 +1274,10 @@ object Artist : TagList { "artist:campbell gichou", "artist:campyo master", "artist:camwoo", + "artist:cancerdoge", "artist:candle", "artist:candychameleon", + "artist:candyfoxy", "artist:cang ye ji", "artist:canon-thought", "artist:capgrolarbear", @@ -1291,6 +1328,7 @@ object Artist : TagList { "artist:cerberus", "artist:cerberuslives", "artist:cerbskies", + "artist:cesar carpio", "artist:cesar rolando lopez castaneda", "artist:cesium", "artist:cevoy", @@ -1306,6 +1344,7 @@ object Artist : TagList { "artist:chalo", "artist:cham22", "artist:chameleon", + "artist:chamu", "artist:chaney su", "artist:chango-tan", "artist:chanpon miyabi", @@ -1317,9 +1356,9 @@ object Artist : TagList { "artist:charie", "artist:charles williams", "artist:charmal", - "artist:chat bleu", "artist:chat noir", "artist:chataro", + "artist:chatbleu3dx", "artist:chauvel", "artist:chawanmushi", "artist:chcrumbles", @@ -1327,6 +1366,7 @@ object Artist : TagList { "artist:cheeky nuttybuns", "artist:cheesy-pie", "artist:cheezyweapon", + "artist:chelodoy", "artist:chemicq", "artist:cherry-gig", "artist:chery in the sun", @@ -1399,6 +1439,7 @@ object Artist : TagList { "artist:chomoyama", "artist:choney", "artist:choomnivoro", + "artist:chou amaki", "artist:chou creme", "artist:chou shippaisaku", "artist:chouchin ankou", @@ -1412,6 +1453,7 @@ object Artist : TagList { "artist:chris3000", "artist:christian darasse", "artist:christian de metter", + "artist:christian godard", "artist:christian paty", "artist:christian zanier", "artist:chujiao", @@ -1485,9 +1527,11 @@ object Artist : TagList { "artist:convard", "artist:cookie lovey", "artist:cool kyou shinja", + "artist:cor369", "artist:cornnell clarke", "artist:corruptking", "artist:corvus pointer", + "artist:cosbi", "artist:cosine", "artist:cosmic", "artist:cosmic vanellope", @@ -1547,6 +1591,7 @@ object Artist : TagList { "artist:cureeper", "artist:curlytopzas", "artist:curvesector", + "artist:custotem", "artist:cuzukago", "artist:cwodrex", "artist:cy.nicism", @@ -1612,11 +1657,13 @@ object Artist : TagList { "artist:daniels k.", "artist:danilo barozzi", "artist:danilo correa", + "artist:dankestofdans", "artist:danp", "artist:danrenji", "artist:dantesward", "artist:dantetsu", "artist:dany", + "artist:daram", "artist:darius-kun", "artist:dark aldebaran", "artist:dark creaturez", @@ -1624,6 +1671,7 @@ object Artist : TagList { "artist:dark molestia", "artist:dark ryev", "artist:dark violet", + "artist:dark-rasp", "artist:darkchibishadow", "artist:darkdp", "artist:darker eve", @@ -1641,7 +1689,6 @@ object Artist : TagList { "artist:darkstardirewolf", "artist:darkuro 27", "artist:darkwaters", - "artist:darth haylee", "artist:darth wave", "artist:daruak", "artist:daruton", @@ -1681,6 +1728,7 @@ object Artist : TagList { "artist:decca19", "artist:dee", "artist:deep purple 72", + "artist:defaultz", "artist:deilan12", "artist:dekamarasu shirokko", "artist:dekosuke 18gou", @@ -1697,6 +1745,7 @@ object Artist : TagList { "artist:denbu momo", "artist:denchi", "artist:denden taiko", + "artist:dendoro kakariya", "artist:denis merezette", "artist:denizen", "artist:denjiryoku", @@ -1770,12 +1819,14 @@ object Artist : TagList { "artist:doahdm", "artist:dobunezumi", "artist:doburocky", + "artist:doco", "artist:doctor", "artist:doctor ellios", "artist:doctor masube", "artist:doctor proxy", "artist:dodai shouji", "artist:dodemoiee", + "artist:dodo-bot", "artist:dodomeiro mayonnaise", "artist:dodomesu3sei", "artist:dogezaemon", @@ -1790,12 +1841,14 @@ object Artist : TagList { "artist:doku corne", "artist:doku-chan", "artist:dokukinokozin", + "artist:dokuneko noil", "artist:dokurosan", "artist:doldolphin", "artist:doll", "artist:doll suke", "artist:dolphin", "artist:dom03", + "artist:domingo roberto mandrafina", "artist:domingues horacio", "artist:dominique saint-marc", "artist:dominique vallet", @@ -1803,7 +1856,6 @@ object Artist : TagList { "artist:donald rust", "artist:donaught", "artist:donkey", - "artist:donnaloli", "artist:donovan mallory", "artist:doobutsu no kodomo", "artist:doom ghost", @@ -1820,6 +1872,7 @@ object Artist : TagList { "artist:doro doneru", "artist:dorota bou", "artist:doru", + "artist:dossei junai", "artist:doublepines", "artist:douglas kim", "artist:douglo", @@ -1828,6 +1881,7 @@ object Artist : TagList { "artist:doyachii", "artist:dpc", "artist:dr badenov", + "artist:dr nihilismo", "artist:dr rex", "artist:dr. comet", "artist:dr. edgar slam", @@ -1846,6 +1900,7 @@ object Artist : TagList { "artist:dragoon tequila", "artist:dragoon-rekka", "artist:drake m. ohkami", + "artist:drake powers", "artist:dramus", "artist:drawmj", "artist:dreadknight0", @@ -1883,6 +1938,7 @@ object Artist : TagList { "artist:e equals mc2", "artist:e-eji", "artist:e-musu aki", + "artist:e. c. segar", "artist:e. e. davis", "artist:e.j. morges", "artist:e.m. ton", @@ -1893,6 +1949,7 @@ object Artist : TagList { "artist:eb110ss", "artist:ebdc", "artist:ebenezer slime", + "artist:ebi riiko", "artist:ebi193", "artist:ebidou", "artist:ebifly", @@ -1918,6 +1975,7 @@ object Artist : TagList { "artist:eddy belly", "artist:edgar sandoval", "artist:edika", + "artist:edkas", "artist:edo nova", "artist:edo shigezu", "artist:edogawa gabal", @@ -1944,6 +2002,9 @@ object Artist : TagList { "artist:eitaisa", "artist:eitchna", "artist:ekakibit", + ) + + override fun getTags2(): List = listOf( "artist:ekataraf", "artist:el at tewi", "artist:el bondage", @@ -1958,6 +2019,7 @@ object Artist : TagList { "artist:elis 120 percent", "artist:eliskalti", "artist:ello", + "artist:elocca", "artist:elsevilla", "artist:eltole", "artist:elton portilho", @@ -1986,6 +2048,7 @@ object Artist : TagList { "artist:endy vatriano", "artist:enigma", "artist:enka shiahara", + "artist:ennmedoo", "artist:eno", "artist:eno akira", "artist:eno yukimi", @@ -2003,9 +2066,6 @@ object Artist : TagList { "artist:epic donburi", "artist:eqamrd", "artist:equidna", - ) - - override fun getTags2() = listOf( "artist:era", "artist:eraanthe", "artist:erbenkranz", @@ -2077,6 +2137,7 @@ object Artist : TagList { "artist:evulchibi", "artist:ewr-115", "artist:ex-buster-wolf", + "artist:exa takahito", "artist:exile factory", "artist:expand-blurples", "artist:extreme", @@ -2132,6 +2193,7 @@ object Artist : TagList { "artist:feuh", "artist:fey tas", "artist:fidchell", + "artist:fiftyfifthfleet", "artist:figgot", "artist:figgylicious", "artist:fight fight chiharu", @@ -2151,6 +2213,8 @@ object Artist : TagList { "artist:fleatrollus", "artist:flick", "artist:flicker show", + "artist:flor", + "artist:flowersimh", "artist:flt", "artist:fluff kevlar", "artist:fluffy pokemon", @@ -2201,6 +2265,7 @@ object Artist : TagList { "artist:fred perry", "artist:frederic bezian", "artist:fredo j", + "artist:fredricton3d", "artist:fredrik k.t. andersson", "artist:free style", "artist:freecree", @@ -2222,6 +2287,7 @@ object Artist : TagList { "artist:fudou ran", "artist:fuetakishi", "artist:fugetsu taku", + "artist:fugubarakun", "artist:fuguri sensen", "artist:fuhma misaki", "artist:fuji katsupiko", @@ -2250,7 +2316,9 @@ object Artist : TagList { "artist:fujimoto gou", "artist:fujimoto haruki", "artist:fujimoto hideaki", + "artist:fujinaga eri", "artist:fujinasu taka", + "artist:fujine yuki", "artist:fujino tobi", "artist:fujino yoshika", "artist:fujinomiya yuu", @@ -2304,10 +2372,12 @@ object Artist : TagList { "artist:furanshisu", "artist:furball", "artist:furburner", + "artist:furfeathertickling", "artist:furipa", "artist:furisuku", "artist:furlana", "artist:furoneka", + "artist:furrpurrv", "artist:furry pinups", "artist:furrymoan", "artist:furu-furu", @@ -2320,6 +2390,7 @@ object Artist : TagList { "artist:fusataka sikibu", "artist:fushigi usagi", "artist:fushiki", + "artist:fushitas", "artist:fusisya o", "artist:futa", "artist:futaba masumi", @@ -2353,6 +2424,7 @@ object Artist : TagList { "artist:g-wara", "artist:g. pinto", "artist:g.b onodera", + "artist:g1", "artist:g13d", "artist:g3ida", "artist:ga one", @@ -2392,6 +2464,8 @@ object Artist : TagList { "artist:gatchapowa", "artist:gatery", "artist:gatorade panda", + "artist:gaz-knightofnylrac", + "artist:geabull", "artist:geekyguy28", "artist:gege-san", "artist:gei oji", @@ -2402,9 +2476,9 @@ object Artist : TagList { "artist:gelatin", "artist:gelmaga", "artist:gemurax", - "artist:genda shou", "artist:gene bilbrew", "artist:genen", + "artist:general-butch", "artist:genha", "artist:genn", "artist:genral sci", @@ -2497,7 +2571,6 @@ object Artist : TagList { "artist:gorilla m", "artist:gorima tsuchio", "artist:goriwednesday", - "artist:goro", "artist:goro ichi", "artist:gorohati", "artist:gorou naoki", @@ -2630,7 +2703,7 @@ object Artist : TagList { "artist:hagane soushi", "artist:hagane tetsu", "artist:hagane type", - "artist:haganef", + "artist:hagane.f", "artist:haganemaru kennosuke", "artist:hagen wolfhowl", "artist:hagetaka", @@ -2692,6 +2765,7 @@ object Artist : TagList { "artist:hanainu", "artist:hanamaki kaeru", "artist:hanamizawa q-tarou", + "artist:hanamoto ari", "artist:hanamura torirou", "artist:hanao.", "artist:hanas", @@ -2719,6 +2793,7 @@ object Artist : TagList { "artist:hara tetsuo", "artist:hara yui", "artist:haracock", + "artist:harada shigemitsu", "artist:harada takehito", "artist:harapeko kakko-nemumari", "artist:harazaki takuma", @@ -2779,6 +2854,7 @@ object Artist : TagList { "artist:hatakeyama tohya", "artist:hataraki ari", "artist:hatch", + "artist:hatikumo rin", "artist:hatimoto", "artist:hato", "artist:hatokonro", @@ -2816,6 +2892,7 @@ object Artist : TagList { "artist:hayato rikin", "artist:haymaker", "artist:hazaki", + "artist:hazama null", "artist:hazuki aoi", "artist:hazuki ayanosuke", "artist:hazuki kai", @@ -2835,6 +2912,7 @@ object Artist : TagList { "artist:heigani", "artist:heijitu", "artist:heiqing langjun", + "artist:hellap", "artist:hellonearth-iii", "artist:helmut kruger", "artist:henkuma", @@ -2888,8 +2966,10 @@ object Artist : TagList { "artist:higashizukihi sei", "artist:hige nii", "artist:higenamuchi", + "artist:higeneko", "artist:higgy", "artist:high heeled jill", + "artist:high-bear", "artist:highfive", "artist:highlow", "artist:highonfairydust", @@ -2977,6 +3057,7 @@ object Artist : TagList { "artist:hirose rika", "artist:hirose souji", "artist:hiroshiki", + "artist:hirota shimaguni", "artist:hirotake awataka", "artist:hirotti", "artist:hiru-kun no ami", @@ -3055,6 +3136,7 @@ object Artist : TagList { "artist:hori airi", "artist:hori hiraki", "artist:hori hiroaki", + "artist:hori kimitsu", "artist:horibe hiderou", "artist:horie tankei", "artist:horihone saizou", @@ -3093,6 +3175,7 @@ object Artist : TagList { "artist:hotei kazuha", "artist:hotkeke", "artist:hotred", + "artist:hotter daimon", "artist:hou", "artist:houjoh akira", "artist:houmatu awa", @@ -3234,6 +3317,7 @@ object Artist : TagList { "artist:ilya kuvshinov", "artist:imaajfpstnfo", "artist:imada hidehito", + "artist:imajin kouji", "artist:imaki hitotose", "artist:imazon", "artist:imilios", @@ -3242,6 +3326,7 @@ object Artist : TagList { "artist:imofuki", "artist:imomushi", "artist:imortal", + "artist:imp underneath", "artist:imsmexyftw", "artist:ina harakiri", "artist:inaba cozy", @@ -3288,6 +3373,7 @@ object Artist : TagList { "artist:inoue tommy", "artist:inoue yoshihisa", "artist:inseki 3gou", + "artist:instanttnoodle", "artist:interstellar", "artist:intoxicatedsquid", "artist:intrigue3d", @@ -3302,6 +3388,7 @@ object Artist : TagList { "artist:inui haruka", "artist:inui nuinu", "artist:inui sekihiko", + "artist:inui slash byte.", "artist:inukami", "artist:inukami inoji", "artist:inukon geek.", @@ -3337,6 +3424,8 @@ object Artist : TagList { "artist:isako rokuroh", "artist:isamatu", "artist:isami nozomi", + "artist:isashii miyo", + "artist:isashinkiro", "artist:isawa nohri", "artist:iseki shuuichi", "artist:ishida sui", @@ -3348,7 +3437,9 @@ object Artist : TagList { "artist:ishii miring", "artist:ishii takamori", "artist:ishii takashi", + "artist:ishikawa akihito", "artist:ishikawa hirodi", + "artist:ishikawa sadahal", "artist:ishikei", "artist:ishimura", "artist:ishinomori kotomi", @@ -3362,6 +3453,7 @@ object Artist : TagList { "artist:isobe toast", "artist:isorashi", "artist:isse", + "artist:isshiki fuji", "artist:issi-13", "artist:issue 69", "artist:isz janeway", @@ -3430,9 +3522,11 @@ object Artist : TagList { "artist:izumi mahiru", "artist:izumi nanase", "artist:izumi rei", + "artist:izumi rion", "artist:izumi sai", "artist:izumi shiina", "artist:izumi tsubasu", + "artist:izumi yakumo", "artist:izumi yayoi", "artist:izumi yuujiro", "artist:izumimori mana", @@ -3459,6 +3553,7 @@ object Artist : TagList { "artist:jack jadson", "artist:jack staller", "artist:jackalope", + "artist:jackarydraws", "artist:jackasss", "artist:jacket freak", "artist:jackie kameyama", @@ -3532,6 +3627,7 @@ object Artist : TagList { "artist:jeibee", "artist:jellytits7", "artist:jenigata", + "artist:jeremy bastian", "artist:jeremy bernal", "artist:jerry t.n. thompson", "artist:jess fink", @@ -3602,10 +3698,12 @@ object Artist : TagList { "artist:john m. pound", "artist:john martello", "artist:john persons", + "artist:john prengaman", "artist:john shinjiro", "artist:john sitch-oh", "artist:johngate", "artist:johnny2dix", + "artist:johnofalltrades", "artist:joixxx", "artist:jojoart", "artist:jolly jack", @@ -3639,6 +3737,7 @@ object Artist : TagList { "artist:joseph caesar s.d.", "artist:joseph farrel", "artist:joseph michael linsner", + "artist:josh the tiger", "artist:josie purr", "artist:josieokami", "artist:josukespimphand", @@ -3660,8 +3759,10 @@ object Artist : TagList { "artist:judas mieko", "artist:judith karla", "artist:judy jong", + "artist:jugganaut", "artist:jul3d", "artist:jules de bruycker", + "artist:julio ribera", "artist:julius zimmerman", "artist:junex2", "artist:junji ito", @@ -3670,6 +3771,7 @@ object Artist : TagList { "artist:junny", "artist:junqspace", "artist:junsui na fujunbutsu", + "artist:junyoh maru", "artist:justin b. addison", "artist:justin long", "artist:justmegabenewell", @@ -3703,6 +3805,7 @@ object Artist : TagList { "artist:kabuki homewood", "artist:kaburagi chiyu", "artist:kacho", + "artist:kada buriko", "artist:kadan", "artist:kadokura miya", "artist:kadomaki shinnosuke", @@ -3770,6 +3873,7 @@ object Artist : TagList { "artist:kakashi asahiro", "artist:kakashi dragon", "artist:kakashichi", + "artist:kakei kei", "artist:kakenashi", "artist:kakeru", "artist:kakimoto kenjirou", @@ -3814,6 +3918,7 @@ object Artist : TagList { "artist:kamiyama aya", "artist:kamogawa tanuki", "artist:kamonari", + "artist:kamoshika ryo", "artist:kamotama", "artist:kamoto", "artist:kamudragon", @@ -3876,6 +3981,7 @@ object Artist : TagList { "artist:kanou seisaku", "artist:kanou soukyuu", "artist:kanoue hiji", + "artist:kanpancake", "artist:kanra karakara", "artist:kanroame", "artist:kantamaki yui", @@ -3899,6 +4005,9 @@ object Artist : TagList { "artist:karasuuri", "artist:karateka value", "artist:karen", + ) + + override fun getTags3(): List = listOf( "artist:karen kyuu", "artist:kari", "artist:karino hasumi", @@ -3929,6 +4038,7 @@ object Artist : TagList { "artist:kashiwamori tama", "artist:kasose", "artist:kassandra leigh purcell", + "artist:kasstt", "artist:kasukabe akira", "artist:kasukabe taro", "artist:kasuki masato", @@ -3989,6 +4099,8 @@ object Artist : TagList { "artist:kawai kenji", "artist:kawai roh", "artist:kawai tamaran", + "artist:kawaii jiro", + "artist:kawajili", "artist:kawakami takashi", "artist:kawamori misaki", "artist:kawamoto hiroshi", @@ -4006,9 +4118,6 @@ object Artist : TagList { "artist:kawatsu kenjiro", "artist:kawazuko chouji", "artist:kawazukuu", - ) - - override fun getTags3() = listOf( "artist:kaya", "artist:kayabanashi", "artist:kayama kifumi", @@ -4019,6 +4128,7 @@ object Artist : TagList { "artist:kayzer", "artist:kazabuki poni", "artist:kazamitiu", + "artist:kazan meu", "artist:kazan no you", "artist:kazasuzu", "artist:kazehaya sora", @@ -4166,6 +4276,7 @@ object Artist : TagList { "artist:kimuti", "artist:kin no tamamushi", "artist:kinbara1099", + "artist:kincyaku tamago", "artist:kindatsu", "artist:kinema tenka", "artist:king of nymphs", @@ -4207,6 +4318,7 @@ object Artist : TagList { "artist:kirimochi nie", "artist:kirimomi shoot", "artist:kirimoto yuuji", + "artist:kirimu latte", "artist:kirin kakeru", "artist:kirinada", "artist:kirino mokutan", @@ -4371,6 +4483,7 @@ object Artist : TagList { "artist:kokujin", "artist:kokuko", "artist:kokumotsu", + "artist:kokumotu suiren", "artist:kokuryuugan", "artist:kokyo k", "artist:komagata", @@ -4398,6 +4511,7 @@ object Artist : TagList { "artist:konata hyuura", "artist:konbu plus", "artist:kondas peter", + "artist:kondoh rururu", "artist:konecha", "artist:konjou natsumi", "artist:konkichi", @@ -4520,6 +4634,7 @@ object Artist : TagList { "artist:kuloamaki", "artist:kuma hachi", "artist:kuma-chan", + "artist:kuma-x", "artist:kumada", "artist:kumada kazushi", "artist:kumamoto aichi", @@ -4534,6 +4649,7 @@ object Artist : TagList { "artist:kumiko", "artist:kumoi takashi", "artist:kumon ryuu", + "artist:kunaboto", "artist:kunaixx", "artist:kunieda saika", "artist:kunitsu takeshi", @@ -4659,8 +4775,10 @@ object Artist : TagList { "artist:kusano kouichi", "artist:kusano takayuki", "artist:kusatsu terunyo", + "artist:kusi zaki", "artist:kusnoha kaede", "artist:kusoniku yokichi", + "artist:kusothumu", "artist:kusoyaza", "artist:kusshii", "artist:kusui aruta", @@ -4760,11 +4878,14 @@ object Artist : TagList { "artist:lento", "artist:leo", "artist:leo fontan", + "artist:leobo", "artist:leonardo 16sei", "artist:leons-7", + "artist:lestart", "artist:leta", "artist:letdie", "artist:lettuce rice", + "artist:lewd saiga", "artist:lewdcactus64", "artist:lewdstuff", "artist:lewis", @@ -4785,6 +4906,7 @@ object Artist : TagList { "artist:linbo", "artist:linda", "artist:link", + "artist:linkz artz", "artist:lionel", "artist:lionel bret", "artist:liquid n", @@ -4799,6 +4921,7 @@ object Artist : TagList { "artist:liveis watanabe", "artist:liver sashi", "artist:lizardbeth", + "artist:lizardlars", "artist:ljrmr", "artist:lock-master", "artist:lockheart", @@ -4844,6 +4967,7 @@ object Artist : TagList { "artist:ls", "artist:luberne", "artist:luca tarlazzi", + "artist:luccatoasty", "artist:lucio filippucci", "artist:lucusold", "artist:lucy fuchs", @@ -4862,6 +4986,7 @@ object Artist : TagList { "artist:lunarez", "artist:lunch", "artist:luolan", + "artist:luxu", "artist:luxurious blue", "artist:lvl3toaster", "artist:lvzergide", @@ -4906,6 +5031,7 @@ object Artist : TagList { "artist:mad rupert", "artist:mad-project", "artist:mada tarou", + "artist:madana", "artist:madbunny", "artist:made from lazers", "artist:madeinheaven", @@ -4931,8 +5057,10 @@ object Artist : TagList { "artist:magaska", "artist:magenta", "artist:maggi", + "artist:magic a2", "artist:magical bandai", "artist:magifuro konnyaku", + "artist:magister", "artist:magnificent arsehole", "artist:magnificent sexy gals", "artist:magnolia-baillon", @@ -4941,6 +5069,7 @@ object Artist : TagList { "artist:maguro teikoku", "artist:mahan.", "artist:mahanmyou", + "artist:mahiru", "artist:mahiruno kagerou", "artist:maicu", "artist:maigleco", @@ -4975,6 +5104,7 @@ object Artist : TagList { "artist:makko reader", "artist:mako", "artist:mako kujira", + "artist:mako3d", "artist:makoto", "artist:makuma ikeru", "artist:malcolm.x", @@ -5022,6 +5152,7 @@ object Artist : TagList { "artist:mara iafew", "artist:marble soda", "artist:marc brunet", + "artist:marc sibel", "artist:marcel gotlib", "artist:marcelo mueller", "artist:marcelo sosa", @@ -5056,6 +5187,7 @@ object Artist : TagList { "artist:marsminer", "artist:martan", "artist:marthasays", + "artist:marti riera", "artist:martin frei", "artist:martincorps", "artist:maru dasshu", @@ -5103,6 +5235,7 @@ object Artist : TagList { "artist:masugitsune", "artist:masujima kensue", "artist:mataaro", + "artist:matanuki", "artist:matashita kintama", "artist:materiarucou", "artist:maternal-reads", @@ -5117,6 +5250,7 @@ object Artist : TagList { "artist:matsu-sensei", "artist:matsuba", "artist:matsubayashi nagana", + "artist:matsuda val", "artist:matsudo aya", "artist:matsue", "artist:matsuka", @@ -5141,6 +5275,7 @@ object Artist : TagList { "artist:matsurika youko", "artist:matsurino naginata", "artist:matsurioka hideyuki", + "artist:matsuriuta", "artist:matsuryu", "artist:matsusaka takeshi", "artist:matsushima namio", @@ -5162,9 +5297,11 @@ object Artist : TagList { "artist:mattro", "artist:matumoto kei", "artist:matuokanili", + "artist:mauricio santoro", "artist:mauro masi", "artist:mavis rooder", "artist:maws-paws", + "artist:max bunker", "artist:max cabanes", "artist:max giwa", "artist:maxblackrabbit", @@ -5207,6 +5344,7 @@ object Artist : TagList { "artist:meguro linu", "artist:meguro sankichi", "artist:mehlewds", + "artist:meima", "artist:meisamu", "artist:mekabu aji max", "artist:mekakushi 490", @@ -5247,6 +5385,7 @@ object Artist : TagList { "artist:mhk", "artist:mi", "artist:mia", + "artist:mianno", "artist:miaspice", "artist:mibry", "artist:mibu natsuki", @@ -5286,8 +5425,10 @@ object Artist : TagList { "artist:miduki monica", "artist:miduki sho", "artist:miduno kenshi", + "artist:miduta nashiko", "artist:mifune seijirou", "artist:migi rider", + "artist:miginer", "artist:miginohito mitsuru", "artist:mignon", "artist:miguel aldasoro", @@ -5421,6 +5562,7 @@ object Artist : TagList { "artist:miranda leigh", "artist:mirco cabbia", "artist:mirin fu-ka", + "artist:mirka andolfo", "artist:mirka lugosi", "artist:miro", "artist:mirror stage", @@ -5597,6 +5739,7 @@ object Artist : TagList { "artist:mmmnomu", "artist:mncncr", "artist:mo", + "artist:mo oku", "artist:moa caret", "artist:moai tentyou", "artist:mocchi au lait", @@ -5637,6 +5780,9 @@ object Artist : TagList { "artist:molokonomi", "artist:molta", "artist:molybdenumgp03", + "artist:momi oji", + "artist:momia hair", + "artist:momitu", "artist:momizi inori", "artist:momizi-kei", "artist:momo inu", @@ -5650,6 +5796,7 @@ object Artist : TagList { "artist:momoi ryouta", "artist:momoiro manjiru", "artist:momoiro-kun", + "artist:momoko", "artist:momonashi potato", "artist:momono yuuca", "artist:momonohito", @@ -5739,6 +5886,7 @@ object Artist : TagList { "artist:motolog", "artist:motozaki akira", "artist:motsuaki", + "artist:motto and notto", "artist:moulin brush", "artist:mountain gori", "artist:mousou-kun", @@ -5757,6 +5905,7 @@ object Artist : TagList { "artist:mr professor", "artist:mr scrambled", "artist:mr synnerster", + "artist:mr unlucky", "artist:mr. 32", "artist:mr. estella", "artist:mr. got", @@ -5777,6 +5926,7 @@ object Artist : TagList { "artist:mrsmancuspia", "artist:mrswindle94", "artist:mrwes", + "artist:mrzapster", "artist:ms-john", "artist:ms-seven0", "artist:msl", @@ -5784,6 +5934,8 @@ object Artist : TagList { "artist:mt", "artist:mtno", "artist:mu-inu475", + "artist:mu-q", + "artist:mubi juno", "artist:mucchiri chanbon", "artist:mucco", "artist:mucha", @@ -5792,6 +5944,7 @@ object Artist : TagList { "artist:muffinmajima", "artist:mugen no ossan", "artist:mugen-dai", + "artist:mugicya world", "artist:muhboobz", "artist:muhny", "artist:muichimon", @@ -5855,159 +6008,5 @@ object Artist : TagList { "artist:mutsuki", "artist:mutsuki lime", "artist:mutsuki ooyashima", - "artist:mutsuki tsutomu", - "artist:mutsutake", - "artist:mutuki shin", - "artist:mutumi", - "artist:mutunari", - "artist:mv", - "artist:mw", - "artist:mx2j", - "artist:myanie", - "artist:myanko64", - "artist:mydirtydrawings", - "artist:myheartpumpspiss", - "artist:myke greywolf", - "artist:mylf3d", - "artist:myohjin tsubasa", - "artist:myrage", - "artist:myrho", - "artist:mysterious joe", - "artist:myuk", - "artist:myuratch", - "artist:mz09", - "artist:n. dofline", - "artist:n.o. chachamaru", - "artist:n.w.f.", - "artist:n0ncanon", - "artist:n6str6m6", - "artist:n820", - "artist:na-nu", - "artist:nabakaine", - "artist:nabeshiki", - "artist:nabeshima mike", - "artist:nabriales the majestic", - "artist:nacho fernandez", - "artist:nadaka harutsugu", - "artist:nadareishi", - "artist:nadzuka", - "artist:naga", - "artist:nagai go", - "artist:nagai wataru", - "artist:nagaikusa", - "artist:nagano akane", - "artist:nagano mamoru", - "artist:nagao yamahiko", - "artist:nagaraya", - "artist:nagare", - "artist:nagare hyo-go", - "artist:nagareboshi", - "artist:nagasaki biidoro", - "artist:nagase haruhito", - "artist:nagase rurio", - "artist:nagashima chosuke", - "artist:nagasio", - "artist:nagatoro sei", - "artist:nagatsuki futsuka", - "artist:nagatsuki misoka", - "artist:nagayama yuunon", - "artist:nagi haruka", - "artist:nagi ichi", - "artist:nagisano usagi", - "artist:nagisawa you", - "artist:nagita tooko", - "artist:naglfar", - "artist:nago nayuta", - "artist:nago.k", - "artist:nagominto", - "artist:nagoyacochin", - "artist:nagumo haruka", - "artist:naha 78", - "artist:nai al", - "artist:naito loveca", - "artist:naito tomoaki", - "artist:naitou gura", - "artist:naitou ryuu", - "artist:naitou satoshi", - "artist:najiga nameta", - "artist:najima keiji", - "artist:naka shinobu", - "artist:nakadera akira", - "artist:nakaduki yuuna", - "artist:nakafusa momo", - "artist:nakagawa you", - "artist:nakagomi", - "artist:nakahara yozy", - "artist:nakahira masahiko", - "artist:nakajima akihiko", - "artist:nakajima atsuko", - "artist:nakajima fumio", - "artist:nakajima rei", - "artist:nakajima tomoki", - "artist:nakajima yuka", - "artist:nakakawa a", - "artist:nakamori itto", - "artist:nakamura hirofumi", - "artist:nakamura hisashi", - "artist:nakamura kafka", - "artist:nakamura nishiki", - "artist:nakamura regura", - "artist:nakamura sakyou", - "artist:nakamura subaru", - "artist:nakamura touya", - "artist:nakamura uzuki", - "artist:nakamura zeus", - "artist:nakano sora", - "artist:nakano tomokazu", - "artist:nakanoo kei", - "artist:nakao hamu", - "artist:nakata mitsuru", - "artist:nakata modem", - "artist:nakata shunpei", - "artist:nakata yumi", - "artist:nakatani nio", - "artist:nakatsu kenji", - "artist:nakatsukasa shou", - "artist:nakayama masaaki", - "artist:nakayama miyuki", - "artist:nakayama tetsugaku", - "artist:nakazato ameri", - "artist:nako mameta", - "artist:nakoudo", - "artist:nakta", - "artist:nakura yasuhiro", - "artist:namae renraku", - "artist:namagaki okami", - "artist:namahagure", - "artist:namakura makibishi", - "artist:namaman", - "artist:namamo nanase", - "artist:namauni", - "artist:namboku", - "artist:name john", - "artist:name runao", - "artist:namekata tubame", - "artist:nameless", - "artist:nameless peasant", - "artist:nami", - "artist:namiyosi", - "artist:nana gawa no ramu", - "artist:nana shinshi", - "artist:nanaca mai", - "artist:nanae", - "artist:nanae akio", - "artist:nanagami you", - "artist:nanahara fuyuki", - "artist:nanahoshi akari", - "artist:nanakagi satoshi", - "artist:nanakawa roduka", - "artist:nanaki seijyu", - "artist:nanakichi", - "artist:nanamatsu kenji", - "artist:nanami natuki", - "artist:nanami shizuka", - "artist:nanamiya 723", - "artist:nanao anzu", - "artist:nanao naru", ) } diff --git a/app/src/main/java/exh/eh/tags/Artist2.kt b/app/src/main/java/exh/eh/tags/Artist2.kt index 030eea9d4..01c4ffa9a 100644 --- a/app/src/main/java/exh/eh/tags/Artist2.kt +++ b/app/src/main/java/exh/eh/tags/Artist2.kt @@ -1,8 +1,164 @@ package exh.eh.tags object Artist2 : TagList { - - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( + "artist:mutsuki tsutomu", + "artist:mutsutake", + "artist:mutuki shin", + "artist:mutumi", + "artist:mutunari", + "artist:mv", + "artist:mw", + "artist:mx2j", + "artist:myanie", + "artist:myanko64", + "artist:mydirtydrawings", + "artist:myheartpumpspiss", + "artist:myke greywolf", + "artist:mylf3d", + "artist:myohjin tsubasa", + "artist:myrage", + "artist:myrho", + "artist:mysterious joe", + "artist:myuk", + "artist:myuratch", + "artist:mz09", + "artist:n. dofline", + "artist:n.o. chachamaru", + "artist:n.w.f.", + "artist:n0ncanon", + "artist:n6str6m6", + "artist:n820", + "artist:na-nu", + "artist:nabakaine", + "artist:nabeshiki", + "artist:nabeshima mike", + "artist:nabriales the majestic", + "artist:nacho fernandez", + "artist:nadaka harutsugu", + "artist:nadareishi", + "artist:nadzuka", + "artist:naga", + "artist:nagai go", + "artist:nagai wataru", + "artist:nagaikusa", + "artist:nagano akane", + "artist:nagano mamoru", + "artist:nagao yamahiko", + "artist:nagaraya", + "artist:nagare", + "artist:nagare hyo-go", + "artist:nagareboshi", + "artist:nagasaki biidoro", + "artist:nagase haruhito", + "artist:nagase rurio", + "artist:nagashima chosuke", + "artist:nagasio", + "artist:nagatoro sei", + "artist:nagatsuki futsuka", + "artist:nagatsuki misoka", + "artist:nagayama yuunon", + "artist:nagi haruka", + "artist:nagi ichi", + "artist:nagio", + "artist:nagisano usagi", + "artist:nagisawa you", + "artist:nagita tooko", + "artist:naglfar", + "artist:nago nayuta", + "artist:nago.k", + "artist:nagominto", + "artist:nagoyacochin", + "artist:nagumo haruka", + "artist:naha 78", + "artist:nai al", + "artist:naikoji", + "artist:naito loveca", + "artist:naito tomoaki", + "artist:naitou gura", + "artist:naitou ryuu", + "artist:naitou satoshi", + "artist:najiga nameta", + "artist:najima keiji", + "artist:naka shinobu", + "artist:nakadera akira", + "artist:nakaduki yuuna", + "artist:nakafusa momo", + "artist:nakagawa you", + "artist:nakagomi", + "artist:nakahara yozy", + "artist:nakahira masahiko", + "artist:nakajima akihiko", + "artist:nakajima atsuko", + "artist:nakajima fumio", + "artist:nakajima rei", + "artist:nakajima tomoki", + "artist:nakajima yuka", + "artist:nakakawa a", + "artist:nakamori itto", + "artist:nakamura hirofumi", + "artist:nakamura hisashi", + "artist:nakamura kafka", + "artist:nakamura nishiki", + "artist:nakamura regura", + "artist:nakamura sakyou", + "artist:nakamura subaru", + "artist:nakamura touya", + "artist:nakamura uzuki", + "artist:nakamura zeus", + "artist:nakano sora", + "artist:nakano tomokazu", + "artist:nakanoo kei", + "artist:nakao hamu", + "artist:nakata mitsuru", + "artist:nakata modem", + "artist:nakata shunpei", + "artist:nakata yumi", + "artist:nakatani nio", + "artist:nakatsu kenji", + "artist:nakatsukasa shou", + "artist:nakayama masaaki", + "artist:nakayama miyuki", + "artist:nakayama tetsugaku", + "artist:nakazato ameri", + "artist:nakimayo", + "artist:nako mameta", + "artist:nakoudo", + "artist:nakta", + "artist:nakura yasuhiro", + "artist:namae renraku", + "artist:namagaki okami", + "artist:namahagure", + "artist:namakura makibishi", + "artist:namaman", + "artist:namamo nanase", + "artist:namauni", + "artist:namboku", + "artist:name john", + "artist:name runao", + "artist:namekata tubame", + "artist:nameless", + "artist:nameless peasant", + "artist:nami", + "artist:namiyosi", + "artist:nana gawa no ramu", + "artist:nana shinshi", + "artist:nanaca mai", + "artist:nanae", + "artist:nanae akio", + "artist:nanagami you", + "artist:nanahara fuyuki", + "artist:nanahoshi akari", + "artist:nanakagi satoshi", + "artist:nanakawa roduka", + "artist:nanaki seijyu", + "artist:nanakichi", + "artist:nanamatsu kenji", + "artist:nanami natuki", + "artist:nanami shizuka", + "artist:nanamiya 723", + "artist:nanao anzu", + "artist:nanao naru", "artist:nanase jun", "artist:nanase makoto", "artist:nanase masato", @@ -87,6 +243,7 @@ object Artist2 : TagList { "artist:naughty hijabista 3dx", "artist:naughtytinkerer", "artist:nauth le roy", + "artist:nauvvii", "artist:nayoshi", "artist:nayunata", "artist:nayuta", @@ -94,6 +251,7 @@ object Artist2 : TagList { "artist:nc", "artist:ndc", "artist:nebo", + "artist:necdaz", "artist:necoto rina", "artist:necro", "artist:necrodrone", @@ -109,6 +267,7 @@ object Artist2 : TagList { "artist:nek0gami", "artist:neko animo", "artist:neko maru rentarou", + "artist:neko no youchuu", "artist:neko samurai", "artist:neko totora", "artist:neko toufu", @@ -143,17 +302,21 @@ object Artist2 : TagList { "artist:nekotantei lux", "artist:nekoyama", "artist:nekoyanagi matasaburou", + "artist:nekoyashiki pushio", + "artist:nemejis", "artist:nemoto mami", "artist:nemunemu", "artist:nemureru usagi 06", "artist:nemuri taiyo", "artist:nendo.", + "artist:neneneg", "artist:neo black", "artist:neo gentle", "artist:neo geppetto", "artist:neo jared", "artist:neocoill", "artist:neodemons", + "artist:neoguoguko", "artist:neoneet", "artist:nerddesign", "artist:nerdus", @@ -180,11 +343,13 @@ object Artist2 : TagList { "artist:nezirozi", "artist:nezumeta", "artist:nf4", + "artist:ngamaru", "artist:ngmi", "artist:ni theta", "artist:ni-no", "artist:nibiiro shizuka", "artist:nibiirokaden", + "artist:niboshitofu", "artist:nicchi sangyou", "artist:nicchuu", "artist:nice tack", @@ -205,6 +370,7 @@ object Artist2 : TagList { "artist:niimaru yuu", "artist:niisan", "artist:niiyama takashi", + "artist:nijihashi sola", "artist:nijiiro ink", "artist:nijo", "artist:nijyou makoto", @@ -232,6 +398,7 @@ object Artist2 : TagList { "artist:ningyon", "artist:niniidawns", "artist:ninniku", + "artist:nino paru", "artist:ninomiya hikaru", "artist:ninomiya ryouzou", "artist:nira yuyuki", @@ -303,6 +470,7 @@ object Artist2 : TagList { "artist:noda yuuji", "artist:nodame", "artist:nodegama", + "artist:nodo", "artist:noe omi", "artist:nofuture", "artist:nogi makoto", @@ -312,9 +480,12 @@ object Artist2 : TagList { "artist:noir", "artist:noise", "artist:noisetanker", + "artist:nokemy", + "artist:noki kuzuri", "artist:nokishita negio", "artist:nom noh", "artist:nomeeo", + "artist:nomiya tomoka", "artist:nomura mizuki", "artist:nomura ryouji", "artist:non-kong", @@ -324,6 +495,7 @@ object Artist2 : TagList { "artist:nonjake", "artist:nonohara miki", "artist:nonomura hideki", + "artist:noodlenood", "artist:nook lom", "artist:noomi bernadotte", "artist:noparu", @@ -333,6 +505,7 @@ object Artist2 : TagList { "artist:norakuro nero", "artist:norberto fernandez", "artist:nord fantasy", + "artist:nori gorou", "artist:nori heita", "artist:nori norisuke", "artist:nori tamago", @@ -391,9 +564,11 @@ object Artist2 : TagList { "artist:o yat", "artist:o-ide chosuke", "artist:o-ji", + "artist:o-mac", "artist:o-ro", "artist:o.davis", "artist:o.p com", + "artist:oad", "artist:oaf", "artist:oaks", "artist:oba yoshifumi", @@ -497,6 +672,7 @@ object Artist2 : TagList { "artist:okawa wataru", "artist:okayu", "artist:okayusan", + "artist:okazaki joe", "artist:okazaki mituki", "artist:okazaki takeshi", "artist:oke", @@ -506,9 +682,11 @@ object Artist2 : TagList { "artist:okingjo", "artist:okino matsushiro", "artist:okiraku nic", + "artist:okita yuuho", "artist:okiyo", "artist:okome gang", "artist:okometsubu", + "artist:oksandio", "artist:oku hiroya", "artist:oku tamamusi", "artist:okuma masami", @@ -532,10 +710,12 @@ object Artist2 : TagList { "artist:om", "artist:omaru gyuunyuu", "artist:omega zuel", + "artist:omi shinano", "artist:omiart", "artist:omny87", "artist:omori unko", "artist:on", + "artist:on fan", "artist:onaka sukisuki", "artist:onat", "artist:once and again", @@ -561,6 +741,7 @@ object Artist2 : TagList { "artist:onyxsis", "artist:oo sebastian oo", "artist:oo umigarasu", + "artist:ooban yaki", "artist:oobanburumai", "artist:oobari masami", "artist:oobayashi mori", @@ -680,12 +861,14 @@ object Artist2 : TagList { "artist:ottorisu", "artist:otty the notty", "artist:otumaru", + "artist:oudo mikito", "artist:oujano kaze", "artist:ouji hiyoko", "artist:ouka sushi", "artist:ouka zero shiki", "artist:oukazero", "artist:ouma tokiichi", + "artist:oumikun", "artist:ounwm", "artist:ourflatcoat", "artist:ousawa kanata", @@ -759,6 +942,7 @@ object Artist2 : TagList { "artist:pastel", "artist:pata", "artist:patanu", + "artist:patientz", "artist:patiroku", "artist:patrice killoffer", "artist:patrick gainher", @@ -780,11 +964,14 @@ object Artist2 : TagList { "artist:pee kay", "artist:pekepoko", "artist:peko", + "artist:pekoni", "artist:pen", "artist:pencil", "artist:penguindou", "artist:penname wa nai", + "artist:pepamintopatty", "artist:peparon", + "artist:pepe boada", "artist:pepper0", "artist:peregrine", "artist:perfect queentsunade", @@ -830,6 +1017,7 @@ object Artist2 : TagList { "artist:picao", "artist:pickles", "artist:pie", + "artist:pier carlo macchi", "artist:pier dario pennati", "artist:piero", "artist:pierre dupuis", @@ -840,6 +1028,7 @@ object Artist2 : TagList { "artist:pikuru", "artist:pingkypen", "artist:pink", + "artist:pink alucard", "artist:pink no piyo piyo", "artist:pink pawg", "artist:pinta", @@ -889,12 +1078,15 @@ object Artist2 : TagList { "artist:ponkosfm", "artist:ponkotsu", "artist:ponkotsu y4", + "artist:ponnyu", "artist:ponyanony", "artist:ponz", + "artist:poofroom", "artist:poorgom", "artist:pop", "artist:pop room", "artist:popeye", + "artist:poppezinga", "artist:poriuretan", "artist:pornomagnum", "artist:poruserin", @@ -933,6 +1125,7 @@ object Artist2 : TagList { "artist:psp3dass", "artist:psycho", "artist:psycho comic j", + "artist:psychostuff", "artist:psycocko", "artist:psycodraws", "artist:ptarouh", @@ -946,6 +1139,7 @@ object Artist2 : TagList { "artist:punishedkom", "artist:punk-pegasus", "artist:puranpuman", + "artist:purepervert", "artist:purfect princessgirl", "artist:puribou", "artist:purin a la mode", @@ -981,6 +1175,7 @@ object Artist2 : TagList { "artist:queencomplex", "artist:quickdraw", "artist:qunami himehiko", + "artist:qundium", "artist:qutouten", "artist:qys3", "artist:r", @@ -1000,6 +1195,7 @@ object Artist2 : TagList { "artist:rabies t lagomorph", "artist:rached", "artist:radasus nailo", + "artist:radio bx", "artist:radio ga ga", "artist:radiohead", "artist:raffaele marinetti", @@ -1109,6 +1305,7 @@ object Artist2 : TagList { "artist:reine", "artist:reiq", "artist:reirei", + "artist:reissence", "artist:reit", "artist:reitou dentai", "artist:rekaerb maerd", @@ -1148,11 +1345,13 @@ object Artist2 : TagList { "artist:rihito", "artist:rihito akane", "artist:rikka kai", + "artist:rikoko", "artist:riku maru", "artist:rikudou koushi", "artist:rikudou maki", "artist:rikumoto yoshiyuki", "artist:rikusu", + "artist:rilex lenov", "artist:rileyav", "artist:rimiera", "artist:rimviolet", @@ -1234,7 +1433,7 @@ object Artist2 : TagList { "artist:rottencat", "artist:roudoc 2-gou", "artist:rougetu", - "artist:row", + "artist:rounds chen", "artist:rox chien", "artist:roxane jeong", "artist:roy mccloud", @@ -1336,11 +1535,14 @@ object Artist2 : TagList { "artist:s.o.s.", "artist:s.p.k", "artist:s.r.i.", + "artist:s8403", + "artist:sa.te.", "artist:saba ibaru", "artist:saba satoru", "artist:sabaku", "artist:sabanoniwatori", "artist:sabashi renya", + "artist:saberkenji", "artist:sabretoothedermine", "artist:sabu", "artist:saburou", @@ -1394,6 +1596,7 @@ object Artist2 : TagList { "artist:saitani umetarou", "artist:saite kei", "artist:saito chiho", + "artist:saito naoki", "artist:saito sakae", "artist:saito yahu", "artist:saitoh maho", @@ -1510,9 +1713,10 @@ object Artist2 : TagList { "artist:sanba riwo", "artist:sanbasou", "artist:sanbun kyoden", + "artist:sandbox", "artist:sandro angiolini", + "artist:sanehara kurumi", "artist:sanezaki tsukiuo", - "artist:sang ha", "artist:sangoshou", "artist:sangou mitsuru", "artist:sanhualishuwu", @@ -1534,10 +1738,12 @@ object Artist2 : TagList { "artist:sansyoku amido.", "artist:sansyouo", "artist:sant andrea", + "artist:santouka", "artist:sanuki", "artist:saorikiorimi", "artist:saphire nishi", "artist:sara palmer", + "artist:sarachi yomi", "artist:sarah salanica", "artist:saraka s", "artist:sarami ryou", @@ -1549,6 +1755,7 @@ object Artist2 : TagList { "artist:saruasu", "artist:saruei", "artist:saryuu", + "artist:sasaame", "artist:sasachinn", "artist:sasaduka dai", "artist:sasagawa hayashi", @@ -1614,10 +1821,12 @@ object Artist2 : TagList { "artist:sawatari yuuka", "artist:sawatei", "artist:sawayaka samehada", + "artist:saye", "artist:sayo", "artist:sayo tanku", "artist:sayousuke", "artist:sayuhime tatsumi", + "artist:sazaemu", "artist:sazaki ichiri", "artist:sazanami mio", "artist:sb", @@ -1639,6 +1848,7 @@ object Artist2 : TagList { "artist:scriptoromniscius24", "artist:scy 25", "artist:sd bigpie", + "artist:seabones", "artist:sean lang", "artist:seanji sariel", "artist:sebafox", @@ -1699,6 +1909,7 @@ object Artist2 : TagList { "artist:sensouji kinoto", "artist:sentrythe2310", "artist:senzublunt", + "artist:seo miinosuke", "artist:sera tooru", "artist:serei teru", "artist:sergei", @@ -1710,6 +1921,7 @@ object Artist2 : TagList { "artist:seriiif plus", "artist:serikawa kazumi", "artist:seriou sakura", + "artist:serizawa tomo", "artist:serizawa yuuji", "artist:sessa takuma", "artist:sesso nashiko", @@ -1723,12 +1935,14 @@ object Artist2 : TagList { "artist:setuna rio", "artist:setunai porori", "artist:seura isago", + "artist:seven gromwoid", "artist:seven pear", "artist:sexgazer", "artist:sexless2012", "artist:sexy sketches", "artist:sexyturkey", "artist:sezqya", + "artist:sgt-lonely", "artist:sh0r0ken", "artist:shadako26", "artist:shade", @@ -1754,6 +1968,7 @@ object Artist2 : TagList { "artist:shawntae howard", "artist:shaya", "artist:sheela", + "artist:shelby yorda", "artist:shelkopryad", "artist:shelly", "artist:shennai misha", @@ -1767,6 +1982,7 @@ object Artist2 : TagList { "artist:shiba nanasei", "artist:shiba yuuji", "artist:shibahara gotyo", + "artist:shibaken goro", "artist:shibari kana", "artist:shibasaki koh", "artist:shibasaki syouzi", @@ -1786,6 +2002,9 @@ object Artist2 : TagList { "artist:shiden hiro", "artist:shido mayuru", "artist:shiga kenta", + ) + + override fun getTags2(): List = listOf( "artist:shiga retsuto", "artist:shiganai might", "artist:shigehira", @@ -1803,7 +2022,9 @@ object Artist2 : TagList { "artist:shiina soutyou", "artist:shiino", "artist:shiino yuy", + "artist:shiitake taishi", "artist:shiizaki hinaki", + "artist:shiizako you", "artist:shijima yukio", "artist:shijimi", "artist:shijou sadafumi", @@ -1820,6 +2041,7 @@ object Artist2 : TagList { "artist:shikkoku no tsubasa", "artist:shikorisasu", "artist:shima drill", + "artist:shima hokke", "artist:shima kyousuke", "artist:shima syu", "artist:shimachiyo", @@ -1841,6 +2063,7 @@ object Artist2 : TagList { "artist:shimao kazu", "artist:shimashii", "artist:shimataka", + "artist:shimatamago", "artist:shimazaki lem", "artist:shimazu tekko", "artist:shimeji", @@ -1923,6 +2146,7 @@ object Artist2 : TagList { "artist:shiraishi asuka", "artist:shiraishi nagisa", "artist:shiran takashi", + "artist:shiranami kouki", "artist:shirane shiratsuki", "artist:shiraneko itsu", "artist:shirasagi rokuwa", @@ -1975,8 +2199,10 @@ object Artist2 : TagList { "artist:shizukawa shisumi", "artist:shizuki shinra", "artist:shizuki shuya", + "artist:shizuma", "artist:shizumi hanako", "artist:sho-yan", + "artist:shocho", "artist:shogun tanuki", "artist:shoji-ikari", "artist:shojoheart", @@ -2003,9 +2229,6 @@ object Artist2 : TagList { "artist:shourin bonzu", "artist:shousan bouzu", "artist:shoushin sha", - ) - - override fun getTags2() = listOf( "artist:show", "artist:shrums", "artist:shu", @@ -2067,7 +2290,6 @@ object Artist2 : TagList { "artist:sioduke ikura", "artist:siokaze sango", "artist:siomidu", - "artist:siooninco", "artist:sipaktli", "artist:siproites", "artist:siqi", @@ -2105,6 +2327,7 @@ object Artist2 : TagList { "artist:sketchy skylar", "artist:skillet91", "artist:skltn", + "artist:skullworms", "artist:skully", "artist:skwang", "artist:sky", @@ -2173,6 +2396,7 @@ object Artist2 : TagList { "artist:sonoda miyabi", "artist:sonozaki souichi", "artist:sonson-sensei", + "artist:soonsky", "artist:sooperman", "artist:sora inoue", "artist:sorai shinya", @@ -2224,6 +2448,7 @@ object Artist2 : TagList { "artist:speeh", "artist:spelman huto", "artist:spelunkersal", + "artist:sperm ryuuseigun", "artist:spice", "artist:spidu", "artist:spike4072", @@ -2270,10 +2495,13 @@ object Artist2 : TagList { "artist:steven stahlberg", "artist:sticky sheep", "artist:stikyfinkaz", + "artist:stix", "artist:stjepan sejic", "artist:stlemo", + "artist:stogiegoatarts", "artist:stoper", "artist:store at thorurun", + "artist:strange red guy", "artist:strangestquiet", "artist:studio-pirrate", "artist:studioaberration", @@ -2339,6 +2567,7 @@ object Artist2 : TagList { "artist:sunamori yuuta", "artist:sundown", "artist:sunibee", + "artist:sunnyside", "artist:sunset nivaris", "artist:sunshow", "artist:suo grey", @@ -2349,12 +2578,15 @@ object Artist2 : TagList { "artist:superamu k", "artist:superix", "artist:supersoft2", + "artist:supert", + "artist:supertito", "artist:supertomato", "artist:supullim", "artist:suraemon", "artist:suru", "artist:sus woman", "artist:susaki ake", + "artist:sushiyama", "artist:susugu", "artist:susuki", "artist:suta furachina", @@ -2371,6 +2603,7 @@ object Artist2 : TagList { "artist:suzuki jun", "artist:suzuki kimuchi", "artist:suzuki kyoutarou", + "artist:suzuki masahisa", "artist:suzuki mey", "artist:suzuki mira", "artist:suzuki senpai", @@ -2381,7 +2614,7 @@ object Artist2 : TagList { "artist:suzuneco", "artist:suzunone kanata", "artist:suzushiro", - "artist:suzushiro rei", + "artist:suzushiro seri", "artist:suzutsuki kurara", "artist:sw", "artist:swagalicious tony", @@ -2418,6 +2651,7 @@ object Artist2 : TagList { "artist:t-factory", "artist:t-zok", "artist:t.k-1", + "artist:t.y.stars", "artist:ta", "artist:ta-na", "artist:taata", @@ -2457,6 +2691,7 @@ object Artist2 : TagList { "artist:taiger", "artist:taigiakira", "artist:taihei tengoku", + "artist:tailbox", "artist:taira hajime", "artist:taira tsukune", "artist:taishinkokuoh anton", @@ -2512,6 +2747,7 @@ object Artist2 : TagList { "artist:takara kosuke", "artist:takaryoo", "artist:takasaki takemaru", + "artist:takasaki yuuki", "artist:takase muh", "artist:takase rico", "artist:takase yuu", @@ -2520,19 +2756,24 @@ object Artist2 : TagList { "artist:takashiro syouseki", "artist:takashita takashi", "artist:takasugi kou", + "artist:takasumahiro", "artist:takato suzunosuke", "artist:takatoh kazuma", "artist:takatoh sachi", + "artist:takatoh yuko", "artist:takatori umi", "artist:takatou ayumi", "artist:takatou rui", "artist:takatou sora", "artist:takatsu", "artist:takatuki nato", + "artist:takaya n", "artist:takaya natsuki", "artist:takayaki", + "artist:takayama chizu", "artist:takayama toshiaki", "artist:takayamanon", + "artist:takayoshi yuri", "artist:take", "artist:take hiroaki", "artist:take shinshi", @@ -2550,6 +2791,7 @@ object Artist2 : TagList { "artist:takeki michiaki", "artist:takemura sesshu", "artist:takenoko seijin", + "artist:takeoka kosen", "artist:takeoka miho", "artist:takeshita kenjirou", "artist:takeuchi reona", @@ -2558,6 +2800,7 @@ object Artist2 : TagList { "artist:takeuchi takashi", "artist:takewakamaru", "artist:takeyuu", + "artist:takezumi", "artist:taki-dora", "artist:takigawa karin", "artist:takimoto satoru", @@ -2673,6 +2916,7 @@ object Artist2 : TagList { "artist:tatsumi hiroshi", "artist:tatsunami takajin", "artist:tatsunami youtoku", + "artist:tatsunosuke yukiya", "artist:tatsuse yumino", "artist:tatsuya ishida", "artist:tatteinu", @@ -2708,6 +2952,7 @@ object Artist2 : TagList { "artist:teltelhousi", "artist:temix", "artist:tempo gensui", + "artist:temporalwolf", "artist:tempura tamao", "artist:ten", "artist:tenako", @@ -2718,6 +2963,7 @@ object Artist2 : TagList { "artist:tendou kuon", "artist:tendou masae", "artist:teng mai", + "artist:teng zhai zai", "artist:tenjiku rounin", "artist:tenjin hidetaka", "artist:tenjo ryuka", @@ -2725,6 +2971,7 @@ object Artist2 : TagList { "artist:tensa-zangitsu", "artist:tensei-kun", "artist:tenshi juuji", + "artist:tenshi okihana", "artist:tenshinro ryoichi", "artist:tenshou akira", "artist:tentacle monster chu", @@ -2744,8 +2991,10 @@ object Artist2 : TagList { "artist:terashima musi", "artist:terasu mc", "artist:terazip", + "artist:terebi", "artist:teresa richards", "artist:teri terio", + "artist:teritama potekora", "artist:teriyaki", "artist:terrenski", "artist:terry hijiri", @@ -2760,7 +3009,7 @@ object Artist2 : TagList { "artist:tes-mel", "artist:tesan", "artist:teshima nari.", - "artist:test11", + "artist:test12", "artist:tetramax", "artist:tetsubirei", "artist:tetsukui", @@ -2834,6 +3083,7 @@ object Artist2 : TagList { "artist:thorn7", "artist:thorstone", "artist:thousandfoldfeathers", + "artist:threek", "artist:throat", "artist:thunderbat", "artist:tiaz-3dx", @@ -2868,6 +3118,7 @@ object Artist2 : TagList { "artist:tk28", "artist:tksn", "artist:tm", + "artist:to hegemonikon", "artist:to slash let", "artist:toastyco games", "artist:toba yuga", @@ -2926,6 +3177,7 @@ object Artist2 : TagList { "artist:tom smith", "artist:tom tamio", "artist:tom wlod", + "artist:tomato rice", "artist:tomatojigoku", "artist:tomatomato", "artist:tomihero", @@ -2965,6 +3217,7 @@ object Artist2 : TagList { "artist:toontinkerer", "artist:tooyama hikaru", "artist:tooyama kouhaku", + "artist:toph sinex", "artist:tophattruffles", "artist:toradoshi", "artist:torai ryuu", @@ -2992,6 +3245,7 @@ object Artist2 : TagList { "artist:torque", "artist:toru-k", "artist:tosh", + "artist:toshi hiroshi", "artist:toshi.d", "artist:toshiaki", "artist:toshihiro", @@ -3090,6 +3344,7 @@ object Artist2 : TagList { "artist:tsukumo gou", "artist:tsukushino makoto", "artist:tsukuyomi sazin", + "artist:tsumire", "artist:tsumugie", "artist:tsumujikaze", "artist:tsumumaru hifu", @@ -3121,6 +3376,7 @@ object Artist2 : TagList { "artist:tsuzuki masaki", "artist:tsuzura", "artist:tsuzura ryo", + "artist:tttttttt", "artist:ttuunn", "artist:tuan hollaback", "artist:tukamori syuuji", @@ -3149,6 +3405,7 @@ object Artist2 : TagList { "artist:twinpoo", "artist:twistedgrim", "artist:twistedscarlett60", + "artist:twistedted", "artist:two-ton-neko", "artist:tyanaka", "artist:tyarashi", @@ -3176,6 +3433,7 @@ object Artist2 : TagList { "artist:uchoten", "artist:uchuu teiou", "artist:udai tetsurou", + "artist:udimushi", "artist:udon", "artist:udou ryousuke", "artist:uduki takeru", @@ -3230,6 +3488,7 @@ object Artist2 : TagList { "artist:umematsu thomas", "artist:umeo hiromori", "artist:umetani kenji", + "artist:umetsu yasuomi", "artist:umetsu yukinori", "artist:umibe shin", "artist:umihara minato", @@ -3254,6 +3513,7 @@ object Artist2 : TagList { "artist:unknown76sc", "artist:unknownmaru", "artist:unname neko", + "artist:unnero11", "artist:uno makoto", "artist:uno usaya", "artist:unpopularwolf", @@ -3290,7 +3550,9 @@ object Artist2 : TagList { "artist:uri uri", "artist:uron rei", "artist:urotan", + "artist:uruh aqua", "artist:urushihara satoshi", + "artist:urushime", "artist:urutsu", "artist:uruujima call", "artist:us them", @@ -3301,11 +3563,14 @@ object Artist2 : TagList { "artist:usagine kobo", "artist:usami wataru", "artist:usami yuu", + "artist:usanomura kamekichi", "artist:usashiro mani", "artist:uselessboy", + "artist:ushi no shita", "artist:ushigami mitsuki", "artist:ushiho", "artist:ushijima", + "artist:ushikani gassen", "artist:ushita", "artist:uso asio", "artist:usoneko", @@ -3313,12 +3578,14 @@ object Artist2 : TagList { "artist:usui rikaon", "artist:usurai", "artist:usyuuri", + "artist:utage.", "artist:utamaro", "artist:utanone sion", "artist:utatane hiroyuki", "artist:utpalavarna", "artist:utsugi tsuguha", "artist:utsurou", + "artist:uzaki takamaru", "artist:uzakiyu", "artist:uziga waita", "artist:uzuki jun", @@ -3385,6 +3652,7 @@ object Artist2 : TagList { "artist:viviane nicaise", "artist:vizeta", "artist:vkelis", + "artist:vladimiro missaglia", "artist:void nosferatu", "artist:vokatron", "artist:volpe", @@ -3406,6 +3674,7 @@ object Artist2 : TagList { "artist:wade99", "artist:waga na wa masamichi", "artist:waguchi shouka", + "artist:waidhi", "artist:waikke", "artist:waito", "artist:waka", @@ -3423,6 +3692,7 @@ object Artist2 : TagList { "artist:waldemar kazak", "artist:wallace wood", "artist:walter geovani", + "artist:walter m. baumhofer", "artist:walzrj erorider", "artist:wamusato haru", "artist:wanaata", @@ -3451,6 +3721,7 @@ object Artist2 : TagList { "artist:watanabe yoshimasa", "artist:watanuki kaname", "artist:watanuki lon", + "artist:watanuki sui", "artist:watarai kage", "artist:watari kazuya", "artist:watari masahito", @@ -3512,10 +3783,13 @@ object Artist2 : TagList { "artist:wolfy-nail", "artist:woof", "artist:woofy rainshadow", + "artist:woomochichi", + "artist:worky zark", "artist:wossarem", "artist:wotca", "artist:wox yang", "artist:wreck shop", + "artist:writefag", "artist:wrong", "artist:wtparadise", "artist:wu chuang", @@ -3533,9 +3807,12 @@ object Artist2 : TagList { "artist:xc404", "artist:xeladuart", "artist:xentain", + "artist:xeono", "artist:xeph", "artist:xeracx", + "artist:xi yao", "artist:xianetta", + "artist:xiao bai tian", "artist:xiaowoo", "artist:xiaoxi", "artist:xiii", @@ -3589,6 +3866,7 @@ object Artist2 : TagList { "artist:yakuta tetsuya", "artist:yakuzaishi", "artist:yam spectrum", + "artist:yama tachibana", "artist:yamabuki zarame", "artist:yamabukiiro", "artist:yamada akihiro", @@ -3596,6 +3874,7 @@ object Artist2 : TagList { "artist:yamada kosuke", "artist:yamada mario", "artist:yamada no seikatu ga daiichi", + "artist:yamada rei", "artist:yamada sansuke", "artist:yamada shiguma", "artist:yamada shouji", @@ -3691,6 +3970,7 @@ object Artist2 : TagList { "artist:yato hikaru", "artist:yatsuka", "artist:yatsuki akehisa", + "artist:yatuki junichiro", "artist:yaturugi takumi", "artist:yayoi kotoyuki", "artist:yaz malvavisco", @@ -3703,12 +3983,14 @@ object Artist2 : TagList { "artist:yequo", "artist:yes-i-did", "artist:yezhi na", + "artist:yf", "artist:ygo", "artist:yichimo", "artist:yishan studio", "artist:ynorka", "artist:yo-jin", "artist:yo-nashi", + "artist:yochiko", "artist:yodogawa nanko", "artist:yoekosukii", "artist:yog", @@ -3723,6 +4005,9 @@ object Artist2 : TagList { "artist:yoko juusuke", "artist:yoko mawatari", "artist:yokohama inka", + ) + + override fun getTags3(): List = listOf( "artist:yokoi rego", "artist:yokomichigai", "artist:yokonyan", @@ -3761,6 +4046,7 @@ object Artist2 : TagList { "artist:yoshida inuhito", "artist:yoshida kei", "artist:yoshida kunio", + "artist:yoshida mika", "artist:yoshiga fuumi", "artist:yoshihara yuuka", "artist:yoshikawa arata", @@ -3804,6 +4090,7 @@ object Artist2 : TagList { "artist:yousuke", "artist:youtou sadamitsu", "artist:youtsuu 2-gou", + "artist:yozakura sakyou", "artist:yozora shiba", "artist:yslaire", "artist:yu", @@ -3813,12 +4100,14 @@ object Artist2 : TagList { "artist:yubari meronn", "artist:yubeshiru", "artist:yuboot", + "artist:yudeebi", "artist:yuduka", "artist:yuduki ichi", "artist:yuduki kisa", "artist:yudzuki hina", "artist:yue", "artist:yuena", + "artist:yugo", "artist:yuhki hico", "artist:yuhki shinichi", "artist:yui toshiki", @@ -3854,6 +4143,7 @@ object Artist2 : TagList { "artist:yukimaru.", "artist:yukimasa", "artist:yukimino yukio", + "artist:yukinimaru", "artist:yukino ichigo", "artist:yukino minato", "artist:yukino yukikaze", @@ -3873,6 +4163,7 @@ object Artist2 : TagList { "artist:yumano yuuki", "artist:yume kirei", "artist:yumegi atsuki", + "artist:yumeiro rukka", "artist:yumeno hiroshi", "artist:yumeno owari", "artist:yumeno tanuki", @@ -3895,9 +4186,11 @@ object Artist2 : TagList { "artist:yuri peach", "artist:yurihara aki", "artist:yuruya", + "artist:yusa aki", "artist:yusa shirou", "artist:yusatona", "artist:yusha-m", + "artist:yushi quetzalli", "artist:yutoriko", "artist:yuu", "artist:yuu kazakami", @@ -3921,6 +4214,7 @@ object Artist2 : TagList { "artist:yuuki tomoka", "artist:yuuki tsumugi", "artist:yuuki yu", + "artist:yuukis", "artist:yuumi kazuaki", "artist:yuunagi seshina", "artist:yuurei makomo", @@ -3969,6 +4263,7 @@ object Artist2 : TagList { "artist:zaunderground", "artist:zawar", "artist:zdl", + "artist:zeblackballd", "artist:zebodoy", "artist:zeekzag", "artist:zefrableu", @@ -3978,6 +4273,7 @@ object Artist2 : TagList { "artist:zel", "artist:zen migawa", "artist:zenbaymono studio", + "artist:zenchi", "artist:zennith mehathvin", "artist:zeno", "artist:zenosuke", @@ -3985,6 +4281,7 @@ object Artist2 : TagList { "artist:zephid", "artist:zepie", "artist:zeplich", + "artist:zerbebuth", "artist:zerg", "artist:zero punch", "artist:zero tanuki", @@ -4006,12 +4303,10 @@ object Artist2 : TagList { "artist:zigrock", "artist:ziko", "artist:zinan", - ) - - override fun getTags3() = listOf( "artist:zinen", "artist:zingate", "artist:zirahu manbou", + "artist:ziroko", "artist:ziz", "artist:zizi", "artist:zlfnrk", @@ -4031,6 +4326,7 @@ object Artist2 : TagList { "artist:zurikat", "artist:zuririan", "artist:zwesomerachel", + "artist:zwwilzza", "artist:zxc338093", "artist:zyaroh akira", "artist:zyd", diff --git a/app/src/main/java/exh/eh/tags/Character.kt b/app/src/main/java/exh/eh/tags/Character.kt index 4e312e128..f8a19547c 100644 --- a/app/src/main/java/exh/eh/tags/Character.kt +++ b/app/src/main/java/exh/eh/tags/Character.kt @@ -1,8 +1,7 @@ package exh.eh.tags object Character : TagList { - - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( "character:.giffany", "character:001", "character:2b", @@ -10,9 +9,11 @@ object Character : TagList { "character:9s", "character:a2", "character:aayla secura", + "character:abigail marston", "character:abiru kobushi", "character:ace trainer", "character:addam origo", + "character:adele", "character:adele balfette", "character:adelicia lenn mathers", "character:adelle", @@ -135,6 +136,7 @@ object Character : TagList { "character:alchemi alchemivich pinka", "character:alcina dimitrescu", "character:alena", + "character:alex chen", "character:alexa", "character:alexander t. oyajiide", "character:alexandra vasquez", @@ -169,6 +171,7 @@ object Character : TagList { "character:alphard alshua", "character:altera", "character:altessa", + "character:altiera cunningham", "character:alvis e. hamilton", "character:alyx vance", "character:amagiri kazutake", @@ -190,6 +193,7 @@ object Character : TagList { "character:amira hergal", "character:amu", "character:amu hinamori", + "character:amur tiger", "character:amuro ninagawa", "character:amy pond", "character:amy rose", @@ -236,6 +240,7 @@ object Character : TagList { "character:annie parker", "character:ant-man", "character:anti", + "character:antoine d coolette", "character:antonio luini", "character:anya borzakovskaya", "character:anya cocolova", @@ -254,9 +259,11 @@ object Character : TagList { "character:aoi tosaka", "character:aoi yamada", "character:aoko aozaki", + "character:apha tawanroong", "character:aphelandra", "character:apple bloom", "character:applejack", + "character:apprentice illusion magician", "character:april oneil", "character:ara", "character:ara haan", @@ -271,6 +278,7 @@ object Character : TagList { "character:arfoire", "character:aria holmes kanzaki", "character:aria shichijou", + "character:ariane glenys maple", "character:arietta the wild", "character:arika amazake", "character:arin", @@ -286,6 +294,7 @@ object Character : TagList { "character:arresta blanket", "character:arriet", "character:arshes nei", + "character:arthur conan doyle", "character:arthur read", "character:artoria pendragon", "character:artoria pendragon alter", @@ -314,6 +323,7 @@ object Character : TagList { "character:astaroth", "character:aster phoenix", "character:astraea", + "character:asuha kusunoki", "character:asuha touhara", "character:asuka hoshino", "character:asuka kazama", @@ -324,7 +334,6 @@ object Character : TagList { "character:asuka sugo", "character:asuka takizawa", "character:asuka watarai", - "character:asuna", "character:asuna ichinose", "character:asuna kagurazaka", "character:asuna yuuki", @@ -344,6 +353,7 @@ object Character : TagList { "character:audrey smith", "character:aurica nestmile", "character:aurora suya rhys kaymin", + "character:auster", "character:avenger", "character:axel almar", "character:axl low", @@ -378,6 +388,9 @@ object Character : TagList { "character:azalyn goza", "character:azami", "character:azmaria hendric", + "character:azucena rocio quispe", + "character:azuma seren", + "character:azura", "character:azusa azuki", "character:azusa miura", "character:azusa nakajou", @@ -432,6 +445,7 @@ object Character : TagList { "character:belphemon rage mode", "character:ben tennyson", "character:bender bending rodriguez", + "character:bengal tiger", "character:beni-enma", "character:benio adashino", "character:benjamin grimm", @@ -450,6 +464,8 @@ object Character : TagList { "character:biba amatori", "character:big boss", "character:big macintosh", + "character:bijou", + "character:bill goodfellowe", "character:binchou-tan", "character:birdy cephon altera", "character:bisca mulan", @@ -477,6 +493,7 @@ object Character : TagList { "character:bob parr", "character:bobobo-bo bo-bobo", "character:bocchi hitori", + "character:bomb-burst", "character:bonnie rockwaller", "character:booker dewitt", "character:boom-boom", @@ -522,9 +539,11 @@ object Character : TagList { "character:cancer deathmask", "character:candice", "character:candice white adley", + "character:candy smalls", "character:capitana galaxia", "character:captain britain", "character:captain ginyu", + "character:captain hook", "character:cara dune", "character:caren ortensia", "character:carla", @@ -672,6 +691,7 @@ object Character : TagList { "character:cloudy quartz", "character:clover field", "character:clover manson", + "character:cocoloo", "character:cocona", "character:cocona bartel", "character:cocoro yazawa", @@ -699,6 +719,7 @@ object Character : TagList { "character:cotaro yazawa", "character:covid-19", "character:cow girl", + "character:crazy dave", "character:crea dolosera", "character:creditta cash", "character:crimson viper", @@ -792,6 +813,7 @@ object Character : TagList { "character:daisuke jigen", "character:daisy mae yokum", "character:daisy oak", + "character:damian desmond", "character:dan hibiki", "character:dana scully", "character:dancing lady orchid", @@ -849,9 +871,11 @@ object Character : TagList { "character:doremi harukaze", "character:doris rurido", "character:dorothea arnault", + "character:doudanuki masakuni", "character:douglas billingham", "character:douma", "character:dovahkiin", + "character:dr. gero", "character:dr. girlfriend", "character:dr. john a. zoidberg", "character:dr. karin chakwas", @@ -863,6 +887,8 @@ object Character : TagList { "character:draco centauros", "character:drasna", "character:droite", + "character:duca degli abruzzi", + "character:dumon", "character:dusknoir", "character:dutch schaefer", "character:dyute", @@ -935,6 +961,7 @@ object Character : TagList { "character:emiri uchi", "character:emiru nagakura", "character:emma frost", + "character:emma woods", "character:emmeryn", "character:emporio ivankov", "character:empress nashmeira ii", @@ -1009,9 +1036,11 @@ object Character : TagList { "character:felli loss", "character:female knight", "character:female protagonist", + "character:ferb seto", "character:fergie duhamel", "character:ferris eris", "character:fideo ardena", + "character:fine motion", "character:finn", "character:finn the human", "character:fiona", @@ -1117,6 +1146,7 @@ object Character : TagList { "character:ghiaccio", "character:ghost weed", "character:giant leopard plant", + "character:gid lucione deviluke", "character:gil nexdor", "character:gilbert durandal", "character:gilbert g.p. guilford", @@ -1130,18 +1160,24 @@ object Character : TagList { "character:gintoki sakata", "character:girl squirrel", "character:gisen yagyuu", + "character:giuseppe garibaldi", "character:giyuu tomioka", "character:gladiolus", + "character:glamrock freddy", "character:glenn quagmire", + "character:gloria sato", "character:gluko", "character:go-bemiu-gi", "character:goddess alice", "character:godot", "character:goei", + "character:goemon gaap", "character:goh", + "character:gold d. roger", "character:golden darkness", "character:gon freecss", "character:gordo brandt", + "character:gorou", "character:gorou miura", "character:gorou mutsumi", "character:gothetta gothetticus", @@ -1152,6 +1188,7 @@ object Character : TagList { "character:gourry gabriev", "character:grace nam", "character:grace oconnor", + "character:graha tia", "character:grandis granva", "character:gravel", "character:gray", @@ -1187,6 +1224,7 @@ object Character : TagList { "character:hacka doll no.3", "character:hacka doll no.4", "character:hagoromo gitsune", + "character:hajime kokonoi", "character:hajime saitou", "character:hajime shino", "character:hakase shinonome", @@ -1206,6 +1244,7 @@ object Character : TagList { "character:hanako hasegawa", "character:hanako kuroe", "character:hanako oomuro", + "character:hanako urawa", "character:hanamaru kunikida", "character:hanataro yamada", "character:hanayo koizumi", @@ -1230,10 +1269,12 @@ object Character : TagList { "character:haruichi kominato", "character:haruka amami", "character:haruka kawashima", + "character:haruka kito", "character:haruka minami", "character:haruka minato", "character:haruka morishima", "character:haruka nanami", + "character:haruka narumi", "character:haruka nogizaka", "character:haruka oozora", "character:haruka takamori", @@ -1249,6 +1290,7 @@ object Character : TagList { "character:haruto houjo", "character:haruya nagumo", "character:haruyuki arita", + "character:hasshaku-sama", "character:hata no kokoro", "character:hatate himekaidou", "character:hatchan", @@ -1276,6 +1318,7 @@ object Character : TagList { "character:helena douglas", "character:heles", "character:helga sinclair", + "character:hellmaster phibrizzo", "character:hendrik", "character:henriette mystere", "character:henry", @@ -1332,6 +1375,7 @@ object Character : TagList { "character:hinagiku katsura", "character:hinata hyuga", "character:hinata kawamoto", + "character:hinata tachibana", "character:hinata uesato", "character:hinata wakaba", "character:hinoki kasuga", @@ -1368,6 +1412,7 @@ object Character : TagList { "character:honou no heine", "character:hoppou seiki", "character:horizon ariadust", + "character:horkeu kamui", "character:horse chestnut", "character:hotaru ichijou", "character:hotaru shidare", @@ -1389,6 +1434,7 @@ object Character : TagList { "character:hulkling", "character:hungary", "character:huntress", + "character:hyakumantenbara salome", "character:hydra bell", "character:hylia", "character:hyouka kazakiri", @@ -1414,6 +1460,7 @@ object Character : TagList { "character:iggy koopa", "character:ika musume", "character:ikazuchi", + "character:ikemen kamen amai mask", "character:ikolina", "character:iku nagae", "character:iku nakatani", @@ -1488,6 +1535,7 @@ object Character : TagList { "character:jack", "character:jack atlas", "character:jacqli", + "character:jacqueline olantern dupre", "character:jacqui briggs", "character:jaden yuki", "character:jaguar man", @@ -1559,7 +1607,6 @@ object Character : TagList { "character:jubilee", "character:judith neutron", "character:judith snorrevik", - "character:judy hopps", "character:juggernaut", "character:jujuku shunamur", "character:julianne stingray", @@ -1598,6 +1645,7 @@ object Character : TagList { "character:kaede makidera", "character:kaede misumi", "character:kaede nankyoku", + "character:kaede sendoin", "character:kaede takagaki", "character:kaere kimura", "character:kaeya alberich", @@ -1610,8 +1658,10 @@ object Character : TagList { "character:kaguya ootsutsuki", "character:kaguya sumeragi", "character:kaguya yamai", + "character:kaho kuwakami", "character:kaho morii", "character:kai chisaki", + "character:kai hanaoka", "character:kai kyou", "character:kain blueriver", "character:kaisar lidfard", @@ -1620,7 +1670,9 @@ object Character : TagList { "character:kakashi hatake", "character:kakei mihaya", "character:kako-hakase", + "character:kakucho hitto", "character:kakunsa", + "character:kalego naberius", "character:kalifa", "character:kalinka cossack", "character:kallen stadtfeld", @@ -1634,6 +1686,7 @@ object Character : TagList { "character:kanade jinguji", "character:kanade suzutsuki", "character:kanade tachibana", + "character:kanade yoisaki", "character:kanade yuuki", "character:kanae itou", "character:kanae kochou", @@ -1656,6 +1709,7 @@ object Character : TagList { "character:kano sazanami", "character:kanon azai", "character:kanon hatori", + "character:kanon kougami", "character:kanon mizushiro", "character:kanon nakagawa", "character:kanpe-chan", @@ -1691,6 +1745,7 @@ object Character : TagList { "character:karkinos rucan", "character:karnatia seri anabald", "character:kasen ibara", + "character:kasuga maru", "character:kasumi momochi", "character:kasumi tendo", "character:kasumi todoh", @@ -1715,6 +1770,7 @@ object Character : TagList { "character:kaworu nagisa", "character:kaya miyoshi", "character:kazahana", + "character:kazami ryo", "character:kazamori sasa", "character:kazari", "character:kazari uiharu", @@ -1733,6 +1789,7 @@ object Character : TagList { "character:kazuto minaho", "character:kazuya aoi", "character:keena soga", + "character:kei arimori", "character:kei ayamine", "character:kei kishimoto", "character:kei yuuki", @@ -1775,6 +1832,7 @@ object Character : TagList { "character:killer croc", "character:killer t saibou", "character:killua zoldyck", + "character:kim chien le", "character:kimahri ronso", "character:kimi aoi", "character:king dedede", @@ -1785,6 +1843,7 @@ object Character : TagList { "character:kinu himuro", "character:kinuho wannai", "character:kinuyo nishi", + "character:kinzoku bat", "character:kipo oak", "character:kira daidohji", "character:kirakishou", @@ -1805,10 +1864,13 @@ object Character : TagList { "character:kirin toudou", "character:kirina hiura", "character:kirino kousaka", + "character:kirio amy", + "character:kirisato", "character:kiritsugu emiya", "character:kirumi tojo", "character:kiryu kazuma", "character:kiryuu bannanchiten", + "character:kisaki kondou", "character:kisara nanjou", "character:kisuke urahara", "character:kite tenjo", @@ -1819,6 +1881,7 @@ object Character : TagList { "character:kiyone makibi", "character:kl-e-0", "character:klan klan", + "character:klarion the witch boy", "character:klin", "character:klose rinz", "character:kneesocks demon", @@ -1826,6 +1889,7 @@ object Character : TagList { "character:koakuma", "character:kobato haneda", "character:kobato hasegawa", + "character:kobeni yonomori", "character:kobory", "character:koby", "character:kodaka hasegawa", @@ -1840,11 +1904,13 @@ object Character : TagList { "character:koharu shimoe", "character:koheita nanamatsu", "character:kohran li", + "character:kohta hirano", "character:kohza", "character:koichi nanase", "character:koishi herikawa", "character:koishi komeiji", "character:koizumi-san", + "character:kojiro nanjo", "character:kojirou hyuuga", "character:kokkoro", "character:koko hekmatyar", @@ -1872,6 +1938,7 @@ object Character : TagList { "character:kotaro inugami", "character:kotaro nanbara", "character:kotaro ogami", + "character:kotarou higuchi", "character:kotarou katsura", "character:kotetsu t. kaburagi", "character:kotoha kutsugi", @@ -1935,6 +2002,9 @@ object Character : TagList { "character:kukaku shiba", "character:kukuri tachibana", "character:kula diamond", + ) + + override fun getTags2(): List = listOf( "character:kumako kumoike", "character:kumi mikuni", "character:kumin tsuyuri", @@ -1954,6 +2024,7 @@ object Character : TagList { "character:kurumi imari", "character:kurumu kurono", "character:kushina uzumaki", + "character:kushinadahime", "character:kusuha mizuha", "character:kusunoki kasuga", "character:kusunoki sio", @@ -1980,6 +2051,7 @@ object Character : TagList { "character:kyon", "character:kyon no imouto", "character:kyosuke kiryu", + "character:kyosuke yotsuya", "character:kyou fujibayashi", "character:kyouhei kuga", "character:kyouji takahara", @@ -2003,9 +2075,6 @@ object Character : TagList { "character:kyrie elison", "character:kyubey", "character:kyubimon", - ) - - override fun getTags2() = listOf( "character:kyuubei yagyuu", "character:l lawliet", "character:l85a1", @@ -2029,6 +2098,7 @@ object Character : TagList { "character:lamretta", "character:lanas mom", "character:lancer", + "character:lanling wang", "character:laplus darknesss", "character:lara croft", "character:largo potter", @@ -2045,6 +2115,7 @@ object Character : TagList { "character:leaf", "character:leanne", "character:leblanc", + "character:lebreau fermet viralesque", "character:leeloo minai lekatariba-lamina-tchai ekbat de sebat", "character:leena toros", "character:lehm brick", @@ -2070,6 +2141,7 @@ object Character : TagList { "character:leonidas i", "character:leonmitchelli galette des rois", "character:leorio paladiknight", + "character:lera melnikova", "character:leshawna", "character:lettuce midorikawa", "character:letz kobayashi", @@ -2077,6 +2149,7 @@ object Character : TagList { "character:levi ackerman", "character:leviathan", "character:levy mcgarden", + "character:lezard valeth", "character:li xiangfei", "character:li xinlin", "character:li-en", @@ -2097,6 +2170,7 @@ object Character : TagList { "character:liliane", "character:lilica evette", "character:lilica felchenerow", + "character:lilina hinazuki", "character:lilith aensland", "character:lilithmon", "character:lilka eleniak", @@ -2145,8 +2219,10 @@ object Character : TagList { "character:lotton the wizard", "character:lou", "character:louis el bridget", + "character:louise camford", "character:louise francoise le blanc de la valliere", "character:louise halevy", + "character:loux krystas", "character:lu xun", "character:luann van houten", "character:luca angeloni", @@ -2205,12 +2281,15 @@ object Character : TagList { "character:madoka kugimiya", "character:madoka kyouno", "character:maekawa", + "character:mafuyu asahina", "character:mafuyu kirisu", "character:mafuyu oribe", "character:mafuyu shiina", + "character:magami oguchi", "character:magane chikujouin", "character:magillanica lou mayvin", "character:magma", + "character:magnamalo", "character:mahalia merrill", "character:mahiru inami", "character:maho hiyajo", @@ -2222,6 +2301,7 @@ object Character : TagList { "character:mai sakurajima", "character:mai shinomiya", "character:mai shiranui", + "character:mai thi hoang", "character:mai tokiha", "character:mai valentine", "character:maid chou", @@ -2235,6 +2315,7 @@ object Character : TagList { "character:maki tsurumaki", "character:makibano miruru", "character:makie sasaki", + "character:mako hitachi", "character:makoto itou", "character:makoto kikuchi", "character:makoto makimura", @@ -2242,6 +2323,7 @@ object Character : TagList { "character:makoto sawatari", "character:makoto shido", "character:makoto yuuki", + "character:malcolm graves", "character:malicorne de grandpre", "character:malty melromarc", "character:mami mizuno", @@ -2278,6 +2360,7 @@ object Character : TagList { "character:marcille donato", "character:marco bodt", "character:marechiyo oomaeda", + "character:mareyo oomaeda", "character:margaret borowski", "character:marge simpson", "character:margery daw", @@ -2404,6 +2487,7 @@ object Character : TagList { "character:mei mah", "character:mei misaki", "character:mei mishima", + "character:mei raiden", "character:mei sakura", "character:mei terumi", "character:mei zenmyoutsutsumi", @@ -2440,13 +2524,16 @@ object Character : TagList { "character:mexiah furan", "character:meyrin hawke", "character:mezou shouji", + "character:mi-chon shikimori", "character:mia clementis", "character:mia connery", "character:mia fey", + "character:mia taylor", "character:miaya gekkougahara", "character:micchy", "character:michael garret", "character:michelanne mazinsky", + "character:michelle watagi", "character:michiru hyodo", "character:michiru koda", "character:michiru matsushima", @@ -2454,6 +2541,7 @@ object Character : TagList { "character:midge klump", "character:midna", "character:midori imai", + "character:midori ishizaka", "character:midori oono", "character:midori tooyama", "character:midori yamabuki", @@ -2533,6 +2621,7 @@ object Character : TagList { "character:minami obuchi", "character:minami sakurai", "character:minami shimada", + "character:minami toba", "character:minamitsu murasa", "character:minamo katsura", "character:minamo kurosawa", @@ -2562,6 +2651,7 @@ object Character : TagList { "character:mio natsume", "character:mio sakamoto", "character:mion sonozaki", + "character:miori celesta", "character:mipha", "character:mira nygus", "character:mira yamana", @@ -2596,8 +2686,10 @@ object Character : TagList { "character:misogi kumagawa", "character:miss doublefinger", "character:miss fortune", + "character:miss heed", "character:miss kitty", "character:mister fantastic", + "character:mistiora arte", "character:misty tredwell", "character:misuzu kamio", "character:misuzu kusakabe", @@ -2607,6 +2699,7 @@ object Character : TagList { "character:mitsue shijo", "character:mitsuhide akechi", "character:mitsuhiko tsuburaya", + "character:mitsuki bakugou", "character:mitsuki nase", "character:mitsuki sawatari", "character:mitsuki shijou", @@ -2668,6 +2761,7 @@ object Character : TagList { "character:momoko sakura", "character:momoko shigeno", "character:momoko touyoko", + "character:momotarou mikoshiba", "character:momoyo kawakami", "character:mona megistus", "character:mondo ooya", @@ -2681,6 +2775,7 @@ object Character : TagList { "character:montmorency margarita la fere de montmorency", "character:moo-tan", "character:moon dancer", + "character:moon shadow", "character:moose", "character:mordred pendragon", "character:morgan le fay", @@ -2697,9 +2792,11 @@ object Character : TagList { "character:motoyasu kitamura", "character:moukaku", "character:moune", + "character:mount lady", "character:moutoku sousou", "character:mr. carrot cake", "character:mr. gar", + "character:mr. heartland", "character:mr. mime", "character:mr. popo", "character:mr. saturn", @@ -2724,6 +2821,7 @@ object Character : TagList { "character:muneakira yagyuu", "character:muramasa", "character:muramasa senju", + "character:murasaki echizen", "character:murasaki kuhouin", "character:murasaki shion", "character:murrue ramius", @@ -2869,6 +2967,7 @@ object Character : TagList { "character:nico yazawa", "character:nicole chen", "character:nicole the lynx", + "character:nienke meijer", "character:nightingale", "character:nikola tesla", "character:nina ichihara", @@ -2906,6 +3005,7 @@ object Character : TagList { "character:norton campbell", "character:nouhime", "character:nove", + "character:nozomi amano", "character:nozomi kiriya", "character:nozomi kujou", "character:nozomi tojo", @@ -2918,6 +3018,7 @@ object Character : TagList { "character:nuriko", "character:nyamo naamo", "character:nyaruko", + "character:nyatasha nyanners", "character:nyota uhura", "character:ochako uraraka", "character:octavia", @@ -2938,6 +3039,7 @@ object Character : TagList { "character:ono d", "character:onpu segawa", "character:onsa amano", + "character:opal bei fong", "character:ophiuchus shaina", "character:oriana thomson", "character:origami tobiichi", @@ -2973,9 +3075,11 @@ object Character : TagList { "character:park jae-sang", "character:parsee mizuhashi", "character:passionlip", + "character:patch d coolette", "character:patchouli knowledge", "character:patricia reichardt", "character:patricia thompson", + "character:paula jones", "character:paz ortega andrade", "character:pearl fey", "character:pebbles flintstone", @@ -3003,11 +3107,14 @@ object Character : TagList { "character:pharaoh atem", "character:philip j. fry", "character:philip pirrip", + "character:philuffy aingram", "character:phineas flynn", "character:phoenix", "character:phoenix wright", "character:phoron tatara", + "character:picero agares", "character:pidge gunderson", + "character:pieck finger", "character:pikachu", "character:ping hai", "character:pink oomiya", @@ -3017,6 +3124,7 @@ object Character : TagList { "character:pit girl", "character:pitahaya", "character:pixy misa", + "character:piyoko", "character:ple two", "character:pleinair", "character:plusle", @@ -3044,6 +3152,7 @@ object Character : TagList { "character:prier", "character:priestess", "character:prince diamond", + "character:prince of midenhall", "character:princess bean", "character:princess bubblegum", "character:princess cadance", @@ -3060,6 +3169,7 @@ object Character : TagList { "character:princess marie ange", "character:princess of moonbrook", "character:princess peach", + "character:princess pipp petals", "character:princess ruto", "character:princess star butterfly", "character:princess waya", @@ -3077,9 +3187,11 @@ object Character : TagList { "character:projekt melody", "character:protagonist", "character:prussia", + "character:ps5-chan", "character:psylocke", "character:pucchan", "character:pudding charlotte", + "character:puko", "character:pumyra", "character:punchline", "character:pyotr ilyich tchaikovsky", @@ -3089,6 +3201,7 @@ object Character : TagList { "character:qoone", "character:queen aleena hedgehog", "character:queen chrysalis", + "character:queen draco", "character:queen elizabeth", "character:queen grimhilde", "character:queen marlena", @@ -3151,6 +3264,7 @@ object Character : TagList { "character:ratie curti", "character:ravel phenex", "character:ravness loxaerion", + "character:ray akaba", "character:rayneshia el-arte corwen", "character:re-l mayer", "character:rebecca hawkins", @@ -3178,6 +3292,7 @@ object Character : TagList { "character:reiko mikami", "character:reiko nagase", "character:reiko natsume", + "character:reiko sato-in", "character:reiko takahashi", "character:reimi saionji", "character:reimi sugimoto", @@ -3244,6 +3359,7 @@ object Character : TagList { "character:rikou takitsubo", "character:riku mikami", "character:rikuo", + "character:riley akaba", "character:riley andersen", "character:riley daring", "character:rimu mikogami", @@ -3260,6 +3376,7 @@ object Character : TagList { "character:rin tosaka", "character:rina kurumi", "character:rina ogata", + "character:rindou haitani", "character:rindou kobayashi", "character:ringo akai", "character:ringo noyamano", @@ -3322,8 +3439,11 @@ object Character : TagList { "character:rozalin", "character:rozie", "character:ruben victoriano", + "character:rubeus hagrid", "character:ruby moon", "character:ruby tojo", + "character:rudolph zeppelin iii", + "character:rudy lineback", "character:ruffnut thorston", "character:rui kisugi", "character:ruiko saten", @@ -3386,6 +3506,7 @@ object Character : TagList { "character:saber alter", "character:saber lily", "character:sabre tiger", + "character:sabro sabnock", "character:sachiko koshimizu", "character:sachiko ogasawara", "character:sadao maou", @@ -3435,6 +3556,7 @@ object Character : TagList { "character:saku tooyama", "character:sakuno uryuu", "character:sakura haruno", + "character:sakura igarashi", "character:sakura igawa", "character:sakura kanou", "character:sakura kasugano", @@ -3527,6 +3649,7 @@ object Character : TagList { "character:scheris adjani", "character:scolipede", "character:scotch broom", + "character:scp-4960", "character:scrooge mcduck", "character:sei asagiri", "character:seifer almasy", @@ -3561,7 +3684,6 @@ object Character : TagList { "character:sensui seiki", "character:sensui shinseiki", "character:sentouin roku-gou", - "character:sentouki - raye", "character:sentouki - roze", "character:senzou tachibana", "character:seolla schweizer", @@ -3639,6 +3761,7 @@ object Character : TagList { "character:shino sousaki", "character:shinobu jacobs", "character:shinobu kochou", + "character:shinobu kuki", "character:shinobu maehara", "character:shinobu miyake", "character:shinobu nunotaba", @@ -3677,6 +3800,7 @@ object Character : TagList { "character:shizuku ashuu", "character:shizuku hazuki", "character:shizuku kitayama", + "character:shizuku kuroe", "character:shizuku oikawa", "character:shizuku sangou", "character:shizumaru hisame", @@ -3685,7 +3809,9 @@ object Character : TagList { "character:shizuru hibara", "character:shobu kirifuda", "character:shoebill", + "character:shoka sakurane", "character:shoko sashinami", + "character:shoma sawamura", "character:shou ashikawa", "character:shou hinakawa", "character:shou toramaru", @@ -3724,6 +3850,7 @@ object Character : TagList { "character:shuusei kagari", "character:shuusekichi seiki", "character:shy guy", + "character:sid chang", "character:sideshow bob", "character:sieglinde baumgard", "character:siesta", @@ -3739,6 +3866,7 @@ object Character : TagList { "character:sisudatu", "character:siune", "character:sivil", + "character:sky striker ace - raye", "character:skycat", "character:skyla", "character:slaanesh", @@ -3784,6 +3912,7 @@ object Character : TagList { "character:souji okita", "character:soukou kuuboki", "character:souma yukihira", + "character:sousei arakida", "character:souseiseki", "character:soushi miketsukami", "character:soushun murasame", @@ -3812,16 +3941,20 @@ object Character : TagList { "character:starlight", "character:starsha iscandar", "character:stella loussier", + "character:steph gingrich", "character:stephanie dola", "character:sterling malory archer", + "character:steven armstrong", "character:steven boxleitner", "character:sticks the badger", "character:stocking anarchy", "character:storm", + "character:su-chan", "character:subaru konoe", "character:subaru mikage", "character:subaru nakajima", "character:subaru natsuki", + "character:subaru wakaba", "character:subway boss ingo", "character:suelecia zagan analeit", "character:sugoi doppai", @@ -3872,6 +4005,9 @@ object Character : TagList { "character:suzune saijou", "character:suzuno kamazuki", "character:suzuya tohzuki", + ) + + override fun getTags3(): List = listOf( "character:sweetie belle", "character:sweetie drops", "character:sword maiden", @@ -3892,6 +4028,7 @@ object Character : TagList { "character:szayel aporro granz", "character:t-00 tyrant", "character:t-elos", + "character:t.j. livingston", "character:t.m. opera o", "character:tabitha", "character:tabitha helene orleans de gallia", @@ -3909,6 +4046,8 @@ object Character : TagList { "character:taiga fujimura", "character:taiga kagami", "character:taigei", + "character:taigong wang", + "character:taiju ooki", "character:taiki", "character:taikogane sadamune", "character:tail blue", @@ -3951,6 +4090,7 @@ object Character : TagList { "character:tamamo no mae", "character:tamayo kizaki", "character:tamora jean calhoun", + "character:tang wutong", "character:tanjirou kamado", "character:tanukichi okuma", "character:tapio chatorazawa", @@ -3979,6 +4119,7 @@ object Character : TagList { "character:teletha tessa testarossa", "character:tenchi masaki", "character:teni", + "character:tenka kou", "character:tenma tsukamoto", "character:tenri ayukawa", "character:tensei iida", @@ -4006,9 +4147,6 @@ object Character : TagList { "character:tiana", "character:tianzi", "character:tien", - ) - - override fun getTags3() = listOf( "character:tien shinhan", "character:tieria erde", "character:tiese schtrinen", @@ -4018,6 +4156,7 @@ object Character : TagList { "character:tigress", "character:tikal the echidna", "character:timantha turner", + "character:timido cute", "character:tinker bell", "character:tio plato", "character:tipper taloon", @@ -4028,6 +4167,7 @@ object Character : TagList { "character:tohru adachi", "character:tohru takagami", "character:toma amamiya", + "character:toma inumaru", "character:tommy himi", "character:tomo asama", "character:tomo yamanobe", @@ -4049,11 +4189,13 @@ object Character : TagList { "character:tooru taki", "character:toph bei fong", "character:tora", + "character:torao mido", "character:tori aoi", "character:toshiro hijikata", "character:toshiya satou", "character:toshizou hijikata", "character:totooria helmold", + "character:touji sawaizumi", "character:touji suzuhara", "character:touka itsuki", "character:touka takanashi", @@ -4071,6 +4213,7 @@ object Character : TagList { "character:toyotomi hideyoshi", "character:tracer", "character:trap jaw", + "character:treacle", "character:triana orpheus", "character:trilla suduri", "character:triplicate girl", @@ -4078,6 +4221,7 @@ object Character : TagList { "character:trixie", "character:tron bonne", "character:trunks briefs", + "character:truth", "character:tsubaki miwa", "character:tsubaki oribe", "character:tsubaki takamura", @@ -4111,6 +4255,7 @@ object Character : TagList { "character:tsunami", "character:tsurara oikawa", "character:tsurara shirayuki", + "character:tsurugi kensaki", "character:tsuruko aoyama", "character:tsuruya", "character:tsutomu komano", @@ -4124,6 +4269,7 @@ object Character : TagList { "character:tweek tweak", "character:tweyen", "character:twilight sparkle", + "character:twin turbo", "character:ty lee", "character:type 64", "character:type 95", @@ -4157,6 +4303,7 @@ object Character : TagList { "character:uryuu ishida", "character:urza pranaice", "character:usami", + "character:ushio kofune", "character:ushiwakamaru", "character:uso ewin", "character:usopp", @@ -4178,6 +4325,7 @@ object Character : TagList { "character:velsper", "character:venipede", "character:vento of the front", + "character:vera nair", "character:veronica madaraki", "character:vert farbreton", "character:vestara khai", @@ -4211,10 +4359,12 @@ object Character : TagList { "character:warrior", "character:washu hakubi", "character:wasp", + "character:watson amelia", "character:weather report", "character:wedding peach", "character:wednesday addams", "character:welrod mkii", + "character:wen-li yang", "character:wendi", "character:wendy marvell", "character:wendy o. koopa", @@ -4281,6 +4431,7 @@ object Character : TagList { "character:yasumitsu wakamiya", "character:yasuna oribe", "character:yasutarou hamada", + "character:yawata maru", "character:yayoi fujisawa", "character:yayoi shinozuka", "character:yayoi takatsuki", @@ -4289,6 +4440,7 @@ object Character : TagList { "character:yellow tulip", "character:yggdra yuril artwaltz", "character:yiffany longstocking lalonde harley", + "character:ying swei", "character:ymir", "character:yoda", "character:yoh asakura", @@ -4313,12 +4465,14 @@ object Character : TagList { "character:yoshiko tsushima", "character:yoshiko yamanaka", "character:yoshimi hanakura", + "character:yoshimi ibaragi", "character:yoshimi takenouchi", "character:yoshimoto imagawa", "character:yoshimura haruka", "character:yoshino himekawa", "character:yoshino kousaka", "character:yoshino shimazu", + "character:yoshino tomotake", "character:yoshio kobayashi", "character:yoshioka", "character:yoshitsugu otani", @@ -4411,15 +4565,18 @@ object Character : TagList { "character:yunoha thrul", "character:yura keikain", "character:yuri", + "character:yuri himukai", "character:yuri nakamura", "character:yuri nikaidou", "character:yuri sakazaki", "character:yuri seo", + "character:yuria niguredou", "character:yurika misumaru", "character:yurika toudou", "character:yuriko aoki", "character:yusa nishimori", "character:yuta homura", + "character:yuta okkotsu", "character:yutaro katori", "character:yuty la", "character:yuu", @@ -4435,6 +4592,7 @@ object Character : TagList { "character:yuuhi katagiri", "character:yuuhi mitsurugi", "character:yuuichi aizawa", + "character:yuuichi kayama", "character:yuuichirou kumada", "character:yuuji itadori", "character:yuuka gouha", @@ -4465,7 +4623,9 @@ object Character : TagList { "character:yuuri kozukata", "character:yuuri shibuya", "character:yuusaku fujiki", + "character:yuusuke fujisaki", "character:yuuta hibiki", + "character:yuuta kiryuu", "character:yuuta togashi", "character:yuuto kamishiro", "character:yuuya mirokuji", @@ -4477,6 +4637,7 @@ object Character : TagList { "character:yuzuriha shirase", "character:yylfordt granz", "character:yzma", + "character:z-arc", "character:z1", "character:z3", "character:zaizen touko", diff --git a/app/src/main/java/exh/eh/tags/Cosplayer.kt b/app/src/main/java/exh/eh/tags/Cosplayer.kt index 683f33dfd..a6040e68f 100644 --- a/app/src/main/java/exh/eh/tags/Cosplayer.kt +++ b/app/src/main/java/exh/eh/tags/Cosplayer.kt @@ -1,46 +1,121 @@ package exh.eh.tags object Cosplayer : TagList { - - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( + "cosplayer:abaoyeshituniang", + "cosplayer:ai lei jiang", "cosplayer:akane araragi", + "cosplayer:akemi101xoxo", "cosplayer:aleksandra bodler", + "cosplayer:alicekyo", + "cosplayer:alin ma", + "cosplayer:alisa kiss", + "cosplayer:alodia gosiengfiao", + "cosplayer:amanda welp", + "cosplayer:anastasia komori", "cosplayer:aokotan", + "cosplayer:arisa mizuhara", "cosplayer:arty huang", + "cosplayer:ashiya noriko", "cosplayer:atsuki", + "cosplayer:ayaka matsunaga", + "cosplayer:bailey jay", + "cosplayer:banbanko", "cosplayer:bishoujomom", + "cosplayer:bobbi starr", "cosplayer:carry key", + "cosplayer:charles dera", "cosplayer:chunmomo", + "cosplayer:comonun", + "cosplayer:danielle vedovelli", + "cosplayer:darling cute", + "cosplayer:dillion harper", + "cosplayer:donnaloli", + "cosplayer:evenink", + "cosplayer:fe galvao", + "cosplayer:fluffy nemu", + "cosplayer:franxcos", + "cosplayer:g44 wa kizutsukanai", "cosplayer:gumiho hannya", "cosplayer:hane ame", + "cosplayer:helly von valentine", + "cosplayer:hessakai", + "cosplayer:hey shika", + "cosplayer:higurashi rin", + "cosplayer:himeecosplay", "cosplayer:hinaughtya", "cosplayer:holly wolf", + "cosplayer:imokawa naoko", "cosplayer:iori moe", + "cosplayer:ishikawa asami", + "cosplayer:jaycee", + "cosplayer:jessica nigri", "cosplayer:jill", "cosplayer:kalinka fox", + "cosplayer:kanda midori", "cosplayer:kaya huang", + "cosplayer:kimmie mi", + "cosplayer:kitami eri", + "cosplayer:koyama rikako", + "cosplayer:kqueentsun", + "cosplayer:kurumi.", "cosplayer:kuuko w", "cosplayer:lenfried", + "cosplayer:lewdoart", + "cosplayer:lovelyspacekitten", + "cosplayer:marie-claude bourbonnais", + "cosplayer:meikoui", "cosplayer:miih cosplay", "cosplayer:mikomin", "cosplayer:misa daidai", + "cosplayer:mizhimaoqiu", + "cosplayer:mochizuki eiko", "cosplayer:momoiro reku", "cosplayer:momokun", "cosplayer:nadyasonika", + "cosplayer:neroko kaigan", + "cosplayer:niannian d", + "cosplayer:nicky", + "cosplayer:niyeye", "cosplayer:nora fawn", "cosplayer:octokuro", "cosplayer:oichi", + "cosplayer:okada yui", + "cosplayer:penkarui", + "cosplayer:punk macarroni", + "cosplayer:queenie", + "cosplayer:rio-chan", "cosplayer:rioko", "cosplayer:rocksy light", + "cosplayer:rolyatistaylor", + "cosplayer:saiwari ph", "cosplayer:saku", "cosplayer:sakurai hinoki", + "cosplayer:sandykuroneko", + "cosplayer:saotome love", + "cosplayer:sawaka", + "cosplayer:sexyflowerwater", + "cosplayer:shibuya kaho", "cosplayer:shiro kitsune", "cosplayer:siao ding", "cosplayer:smoettii", + "cosplayer:sneaky", + "cosplayer:soa lianna", + "cosplayer:son yeeun", + "cosplayer:sunnyvier", + "cosplayer:tanaka hitomi", + "cosplayer:tenleid", + "cosplayer:todopokie", + "cosplayer:tsubaki zakuro", + "cosplayer:tsuki desu", + "cosplayer:tyouduki maryou", + "cosplayer:uchida mahiro", "cosplayer:valery himera", "cosplayer:velvet", "cosplayer:wildhoney423", "cosplayer:yume", + "cosplayer:yunocos69", "cosplayer:yuzupyon", + "cosplayer:zara durose", ) } diff --git a/app/src/main/java/exh/eh/tags/Female.kt b/app/src/main/java/exh/eh/tags/Female.kt index 88949e56e..5dd3fd3ac 100644 --- a/app/src/main/java/exh/eh/tags/Female.kt +++ b/app/src/main/java/exh/eh/tags/Female.kt @@ -1,11 +1,13 @@ package exh.eh.tags object Female : TagList { - - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( "female:abortion", "female:absorption", + "female:adventitious mouth", + "female:adventitious penis", "female:adventitious vagina", + "female:afro", "female:age progression", "female:age regression", "female:ahegao", @@ -17,10 +19,13 @@ object Female : TagList { "female:anal birth", "female:anal intercourse", "female:anal prolapse", + "female:analphagia", "female:angel", + "female:animal on animal", "female:animal on furry", "female:animegao", "female:anorexic", + "female:apparel bukkake", "female:apron", "female:armpit licking", "female:armpit sex", @@ -33,8 +38,10 @@ object Female : TagList { "female:bald", "female:ball sucking", "female:balljob", + "female:balls expansion", "female:bandages", "female:bandaid", + "female:bat girl", "female:bbw", "female:bdsm", "female:bear", @@ -47,6 +54,8 @@ object Female : TagList { "female:big balls", "female:big breasts", "female:big clit", + "female:big lips", + "female:big muscles", "female:big nipples", "female:big penis", "female:big vagina", @@ -68,6 +77,7 @@ object Female : TagList { "female:bodystocking", "female:bodysuit", "female:bondage", + "female:braces", "female:brain fuck", "female:breast expansion", "female:breast feeding", @@ -80,6 +90,7 @@ object Female : TagList { "female:butler", "female:cannibalism", "female:cashier", + "female:cat", "female:catfight", "female:catgirl", "female:cbt", @@ -95,11 +106,16 @@ object Female : TagList { "female:christmas", "female:clamp", "female:clit growth", + "female:clit insertion", "female:clit stimulation", "female:clone", + "female:closed eyes", "female:clothed male nude female", + "female:clothed paizuri", + "female:clown", "female:coach", "female:cock ring", + "female:cockphagia", "female:cockslapping", "female:collar", "female:condom", @@ -115,11 +131,13 @@ object Female : TagList { "female:crossdressing", "female:crotch tattoo", "female:crown", + "female:crying", "female:cum bath", "female:cum in eye", "female:cum swap", "female:cumflation", "female:cunnilingus", + "female:cuntbusting", "female:dark nipples", "female:dark sclera", "female:dark skin", @@ -129,6 +147,8 @@ object Female : TagList { "female:deer girl", "female:defloration", "female:demon girl", + "female:denki anma", + "female:detached sleeves", "female:diaper", "female:dick growth", "female:dickgirl on dickgirl", @@ -138,6 +158,8 @@ object Female : TagList { "female:dog", "female:dog girl", "female:doll joints", + "female:dolphin", + "female:domination loss", "female:donkey", "female:double anal", "female:double blowjob", @@ -169,6 +191,7 @@ object Female : TagList { "female:farting", "female:females only", "female:femdom", + "female:fff threesome", "female:fft threesome", "female:filming", "female:fingering", @@ -183,11 +206,13 @@ object Female : TagList { "female:foot insertion", "female:foot licking", "female:footjob", + "female:forced exposure", "female:forniphilia", "female:fox", "female:fox girl", "female:freckles", "female:frog", + "female:frog girl", "female:frottage", "female:fundoshi", "female:furry", @@ -199,11 +224,15 @@ object Female : TagList { "female:gender change", "female:gender morph", "female:ghost", + "female:giant sperm", "female:giantess", "female:gigantic breasts", + "female:gijinka", + "female:giraffe girl", "female:glasses", "female:glory hole", "female:gloves", + "female:goblin", "female:gokkun", "female:gothic lolita", "female:granddaughter", @@ -213,12 +242,14 @@ object Female : TagList { "female:guro", "female:gyaru", "female:gymshorts", + "female:haigure", "female:hair buns", "female:hairjob", "female:hairy", "female:hairy armpits", "female:handicapped", "female:handjob", + "female:hanging", "female:harem", "female:harness", "female:harpy", @@ -237,18 +268,24 @@ object Female : TagList { "female:human cattle", "female:human on furry", "female:humiliation", + "female:hyena girl", "female:impregnation", "female:incest", "female:infantilism", "female:inflation", "female:insect", "female:insect girl", + "female:internal urination", "female:inverted nipples", "female:invisible", + "female:kangaroo", + "female:kappa", "female:kemonomimi", "female:kigurumi pajama", "female:kimono", + "female:kindergarten uniform", "female:kissing", + "female:kneepit sex", "female:kunoichi", "female:lab coat", "female:lactation", @@ -258,6 +295,7 @@ object Female : TagList { "female:layer cake", "female:leash", "female:leg lock", + "female:legjob", "female:leotard", "female:lingerie", "female:lioness", @@ -266,7 +304,10 @@ object Female : TagList { "female:lolicon", "female:long tongue", "female:low bestiality", + "female:low guro", "female:low lolicon", + "female:low scat", + "female:low smegma", "female:machine", "female:maggot", "female:magical girl", @@ -290,20 +331,25 @@ object Female : TagList { "female:minigirl", "female:monkey", "female:monkey girl", + "female:monoeye", "female:monster girl", "female:moral degeneration", "female:mother", "female:mouse", "female:mouse girl", "female:mouth mask", + "female:multimouth blowjob", "female:multiple arms", "female:multiple assjob", "female:multiple breasts", "female:multiple footjob", "female:multiple handjob", + "female:multiple nipples", "female:multiple orgasms", "female:multiple paizuri", "female:multiple penises", + "female:multiple straddling", + "female:multiple vaginas", "female:muscle", "female:muscle growth", "female:nakadashi", @@ -315,6 +361,7 @@ object Female : TagList { "female:nipple birth", "female:nipple expansion", "female:nipple fuck", + "female:nipple stimulation", "female:nose fuck", "female:nose hook", "female:nun", @@ -327,12 +374,16 @@ object Female : TagList { "female:oppai loli", "female:orc", "female:orgasm denial", + "female:otter girl", + "female:oyakodon", "female:paizuri", + "female:panda girl", "female:pantyhose", "female:pantyjob", "female:parasite", "female:pasties", "female:penis birth", + "female:personality excretion", "female:petplay", "female:petrification", "female:phimosis", @@ -364,13 +415,16 @@ object Female : TagList { "female:rape", "female:real doll", "female:reptile", + "female:retractable penis", "female:rhinoceros", "female:rimjob", "female:robot", "female:ryona", "female:saliva", + "female:sarashi", "female:scar", "female:scat", + "female:scat insertion", "female:school gym uniform", "female:school swimsuit", "female:schoolboy uniform", @@ -378,22 +432,29 @@ object Female : TagList { "female:scrotal lingerie", "female:selfcest", "female:sex toys", + "female:shapening", "female:shared senses", "female:shark", + "female:shark girl", + "female:shaved head", "female:sheep", "female:sheep girl", "female:shemale", "female:shibari", + "female:shimaidon", "female:shimapan", "female:shrinking", "female:sister", "female:skinsuit", + "female:skunk girl", "female:slave", "female:sleeping", "female:slime", "female:slime girl", "female:slug", "female:small breasts", + "female:small penis", + "female:smalldom", "female:smegma", "female:smell", "female:smoking", @@ -401,6 +462,7 @@ object Female : TagList { "female:snake", "female:snake girl", "female:snuff", + "female:sockjob", "female:sole dickgirl", "female:sole female", "female:solo action", @@ -412,8 +474,10 @@ object Female : TagList { "female:squirting", "female:ssbbw", "female:stewardess", + "female:stirrup legwear", "female:stockings", "female:stomach deformation", + "female:straitjacket", "female:strap-on", "female:stretching", "female:stuck in wall", @@ -427,10 +491,13 @@ object Female : TagList { "female:table masturbation", "female:tail", "female:tail plug", + "female:tailjob", + "female:tailphagia", "female:tall girl", "female:tanlines", "female:teacher", "female:tentacles", + "female:thick eyebrows", "female:thigh high boots", "female:tiara", "female:tickling", @@ -443,11 +510,13 @@ object Female : TagList { "female:tracksuit", "female:trampling", "female:transformation", + "female:transparent clothing", "female:tribadism", "female:triple anal", "female:triple penetration", "female:triple vaginal", "female:ttf threesome", + "female:ttt threesome", "female:tube", "female:turtle", "female:tutor", @@ -472,7 +541,10 @@ object Female : TagList { "female:waiter", "female:waitress", "female:weight gain", + "female:wet clothes", + "female:whale", "female:whip", + "female:wingjob", "female:wings", "female:witch", "female:wolf", @@ -484,6 +556,7 @@ object Female : TagList { "female:x-ray", "female:yandere", "female:yuri", + "female:zebra", "female:zombie", ) } diff --git a/app/src/main/java/exh/eh/tags/Group.kt b/app/src/main/java/exh/eh/tags/Group.kt index a177cfa83..b915166dd 100644 --- a/app/src/main/java/exh/eh/tags/Group.kt +++ b/app/src/main/java/exh/eh/tags/Group.kt @@ -1,8 +1,7 @@ package exh.eh.tags object Group : TagList { - - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( "group:---", "group:... mou ii desu.", "group:...with my tears.", @@ -72,6 +71,7 @@ object Group : TagList { "group:38.5 c", "group:3d adult comics", "group:3d bdsm dungeon", + "group:3d live", "group:3d pose shuu", "group:3darlings", "group:3dfiends", @@ -402,6 +402,7 @@ object Group : TagList { "group:anakichi", "group:anal crisis", "group:analog store", + "group:analyst freedom", "group:ananwanco", "group:anata o aishite yamazu", "group:anatawo haijindesu", @@ -514,6 +515,7 @@ object Group : TagList { "group:arikui paradise", "group:arinko.", "group:arisan-antenna", + "group:aristogracy", "group:ariyon dou", "group:ark emerald", "group:ark nantoka", @@ -586,6 +588,7 @@ object Group : TagList { "group:asunaro-shiki bakudan", "group:at 1level", "group:at down", + "group:at e.com", "group:at kenkyuujo", "group:at m-gun", "group:at mztm", @@ -690,6 +693,7 @@ object Group : TagList { "group:balklash.", "group:ball colon s", "group:ballet cohort", + "group:bambi", "group:banana koubou", "group:banana musume", "group:banana no kawa", @@ -752,6 +756,7 @@ object Group : TagList { "group:bery manjhr", "group:bessungou", "group:beta houkai", + "group:beta kikaku hanbai", "group:beta na kanzume", "group:betaneta", "group:betsu ni suki janai yo", @@ -829,6 +834,7 @@ object Group : TagList { "group:blue topaz", "group:blue24", "group:bluebox", + "group:bluehistory", "group:bluehot plus", "group:bluejelly", "group:bluemage", @@ -1038,6 +1044,7 @@ object Group : TagList { "group:chikutakudoh", "group:chikuwano kimochi", "group:chikyuugai seimeitai mokyu", + "group:child box", "group:childmaid", "group:childwife", "group:chill-out", @@ -1143,6 +1150,7 @@ object Group : TagList { "group:circle yuki", "group:circlesprocket", "group:citoron soft", + "group:citric acid1350", "group:clammbon", "group:cleanliness.", "group:cleari tei", @@ -1408,6 +1416,7 @@ object Group : TagList { "group:dolcecanto", "group:dollproject", "group:dom joshidan", + "group:donaora", "group:donburi beya", "group:dondondon", "group:dont understand", @@ -1458,6 +1467,7 @@ object Group : TagList { "group:drill", "group:drill biyori", "group:dro-ya", + "group:dropwortbell", "group:drug slash tag slash 21", "group:dual beat", "group:dualtail", @@ -1531,6 +1541,7 @@ object Group : TagList { "group:enshu spirits", "group:entgegen", "group:enuhuo", + "group:enyidou", "group:ephese", "group:epic lust", "group:epicureansyndrome", @@ -1726,6 +1737,7 @@ object Group : TagList { "group:fuwa fuwa pinkchan", "group:fuwamoko honpo", "group:fuwaten", + "group:fuyuzora izumo", "group:fuzukikai", "group:g area", "group:g equals kundow", @@ -1768,9 +1780,11 @@ object Group : TagList { "group:garaku dusk", "group:garakuta shoujo", "group:garakuta-ya", + "group:garasu hokou", "group:garbage", "group:gardening bulldog", "group:garnet-works.", + "group:garunansa mk-2", "group:garyuh-chitai", "group:gas ketsu jinsei", "group:gasshuukoku netamekoru", @@ -1885,6 +1899,7 @@ object Group : TagList { "group:gpen", "group:gpx", "group:grand cross", + "group:grand plie.", "group:graphic l", "group:gravidan", "group:great acta", @@ -1987,6 +2002,9 @@ object Group : TagList { "group:halleluya.", "group:hallenchi planet", "group:hallucigenia", + ) + + override fun getTags2(): List = listOf( "group:halopack", "group:ham string", "group:ham.", @@ -2002,13 +2020,12 @@ object Group : TagList { "group:hamurabi-dou", "group:hamustar", "group:hamusuta-nonikomi", + "group:hana ni arashi.", "group:hana tabako", - ) - - override fun getTags2() = listOf( "group:hana to ribon", "group:hana x mezo", "group:hanafubuki gorilla", + "group:hanahubu", "group:hanaji koubou", "group:hanamachi shimaiten", "group:hanamaru mugen gym", @@ -2037,6 +2054,7 @@ object Group : TagList { "group:happo ryuu", "group:happy birthday", "group:happy flame time", + "group:happy log", "group:happy strawberry", "group:happydrop", "group:happywest", @@ -2136,6 +2154,7 @@ object Group : TagList { "group:hetaretch", "group:hetaruya", "group:heya no sumi.", + "group:hgt labo", "group:hi at skip", "group:hi plus us", "group:hi-b", @@ -2199,6 +2218,7 @@ object Group : TagList { "group:hiroq", "group:hirouguma", "group:hisagoya", + "group:hisou and anchoku", "group:hisuitei", "group:hisyoku no tansansui", "group:hito no fundoshi", @@ -2229,6 +2249,7 @@ object Group : TagList { "group:hokoushayou shingou", "group:hokuroza", "group:holiday school", + "group:home not found", "group:homepie koubou", "group:homerun chaya", "group:homuras r comics", @@ -2248,6 +2269,7 @@ object Group : TagList { "group:hook", "group:hooliganism", "group:horiishi horuto", + "group:horonabe ken", "group:horrorbabecentral", "group:horsetail", "group:hoshi no hako", @@ -2367,6 +2389,7 @@ object Group : TagList { "group:imobatake", "group:imokenpi", "group:imomushi kyouiku madoguchi", + "group:inakahaishin", "group:inaridou shoten", "group:inc satsujinsha", "group:inceton games", @@ -2395,6 +2418,7 @@ object Group : TagList { "group:intoku.info", "group:inudrill.", "group:inukamedou", + "group:inukichi club", "group:inukorohouse", "group:inunabe", "group:inuteikoku", @@ -2414,6 +2438,7 @@ object Group : TagList { "group:isada-ke", "group:isami kaihatsu jigyoudan", "group:isamu. no oheya", + "group:isanayoruho", "group:ishikari shake nabe doukoukai", "group:ishikorodou", "group:ishimuraya", @@ -2460,6 +2485,7 @@ object Group : TagList { "group:jamadai oukoku", "group:janculsoft", "group:jangarian", + "group:jar of elements", "group:jasmin universal village", "group:jeepney.cony", "group:jei c1on-ri", @@ -2535,6 +2561,7 @@ object Group : TagList { "group:k.a.d", "group:k.f.d.", "group:k.o.store", + "group:k.z.z. gundan", "group:k2 company", "group:k2 tomo no kai", "group:k3", @@ -2555,6 +2582,7 @@ object Group : TagList { "group:kaeri no kai 2", "group:kaeru soft", "group:kagaku-shitsu.", + "group:kage mitsu", "group:kagisawadou", "group:kagishippo", "group:kagiyama baking co ltd", @@ -2584,6 +2612,7 @@ object Group : TagList { "group:kaki purin", "group:kakiabura", "group:kakinotanehitotsubu", + "group:kaku shoujo", "group:kakunetu neko punch", "group:kakuzato-ichi", "group:kamaboko higii", @@ -2612,6 +2641,7 @@ object Group : TagList { "group:kangaroo kick", "group:kanimiso pan", "group:kanimiso-tei", + "group:kankitudou", "group:kankituteien", "group:kanmi ningyou", "group:kanmidokoro usb", @@ -2840,12 +2870,14 @@ object Group : TagList { "group:kokkishin", "group:koko sou iu mise janainde", "group:kokochikyuu", + "group:kokonji honpo", "group:kokonoe", "group:kokonokaya", "group:kokonokiya", "group:kokoro ha koi iro", "group:kokoro no bookmark", "group:kokou no gokutsubushi", + "group:koks k yokochou", "group:koku-from-shojo", "group:kokumaro chousei tounyuu", "group:kokuritsu hinanjo", @@ -2916,6 +2948,7 @@ object Group : TagList { "group:kouni yuu", "group:kousaien", "group:kousoku gurihari-tei", + "group:kousoku purin", "group:kouzaka-san to makino jimusho", "group:kouzu shoukai", "group:kouzuya", @@ -3047,8 +3080,10 @@ object Group : TagList { "group:lab-ideas", "group:labomagi", "group:lagrangian-point", + "group:lagunaseca", "group:laikaloid", "group:lala la", + "group:lalapaloosa", "group:lamchat", "group:lamia advisers", "group:landurchin", @@ -3056,6 +3091,7 @@ object Group : TagList { "group:lantern chord", "group:lapis lazuli", "group:lapislazuli triple star", + "group:laser beam", "group:lathimania kyouwakoku", "group:latte chaba", "group:lavenderblue", @@ -3171,6 +3207,7 @@ object Group : TagList { "group:m kichibeya", "group:m plus dilore", "group:m slash k club", + "group:m-i-p", "group:m-keifu", "group:m-koujou", "group:m-lab.", @@ -3460,6 +3497,7 @@ object Group : TagList { "group:mindcontrolcomics", "group:mine slash mine", "group:minemine kikaku", + "group:minimum fuusen", "group:minimum lab", "group:miniomlet ongakudan", "group:minisuka fx", @@ -3481,6 +3519,7 @@ object Group : TagList { "group:misin koujou", "group:misonodenpatou", "group:misoyahonpo", + "group:misssail", "group:misuterutein", "group:misutta", "group:misuzu dennou gijutsukenkyuujo", @@ -3531,6 +3570,7 @@ object Group : TagList { "group:moe hentai", "group:moe hina", "group:moe shoujo ryouiki", + "group:moegara", "group:moeyuki soft", "group:moezilla-gumi", "group:mofu mofu sheep", @@ -3582,6 +3622,7 @@ object Group : TagList { "group:moon night kitten", "group:moon ruler", "group:moonlegacy", + "group:moonlight laboratory", "group:moonrevenge", "group:moonshell", "group:moonsorrow", @@ -3639,6 +3680,7 @@ object Group : TagList { "group:mozuku dokokai", "group:mp", "group:mp0", + "group:mr. hokke", "group:mr.jack plus", "group:mr.k", "group:mr.outside", @@ -3765,6 +3807,7 @@ object Group : TagList { "group:namakura dou", "group:namanecotei", "group:namasute koubou", + "group:namazuchaya", "group:namekataya", "group:nami-nami restaurant", "group:namida no teinen taishoku", @@ -3906,6 +3949,7 @@ object Group : TagList { "group:nekozamedan", "group:nekuronomikon", "group:nel-zel formula", + "group:nemu wa yakiniku ga tabetai", "group:nemurineko", "group:nenashigusa no ie", "group:nendo ningyo", @@ -3961,6 +4005,9 @@ object Group : TagList { "group:nikomark", "group:nikomi omurice", "group:nikoniko company", + ) + + override fun getTags3(): List = listOf( "group:niku ringo", "group:nikubenki seisakusho", "group:nikudan", @@ -4006,9 +4053,6 @@ object Group : TagList { "group:niwatori", "group:niwatori-ya", "group:niwatoritowani", - ) - - override fun getTags3() = listOf( "group:niy koubou", "group:niziro", "group:niziyumedokoro", @@ -4025,6 +4069,7 @@ object Group : TagList { "group:nocohica", "group:nodobotoke kingyo", "group:nogusaw puzzle", + "group:noir jou entrance", "group:nokishita no rakuen.", "group:nomerikomu", "group:nomigoro.", @@ -4040,7 +4085,6 @@ object Group : TagList { "group:norakurari.", "group:noraneko koubou", "group:noraneko-no-tama", - "group:nori5rou", "group:norihee ginjou", "group:noritama-gozen", "group:norn", @@ -4175,6 +4219,7 @@ object Group : TagList { "group:omusubi koubou", "group:on my way", "group:on-show", + "group:onabe no naka.", "group:onaka suita domei", "group:onasuga 99-yen", "group:one dollar", @@ -4220,6 +4265,7 @@ object Group : TagList { "group:ororiya enpitsudo", "group:osanagokoro no kimi ni", "group:osaru-san panic", + "group:oshaburi tengoku", "group:oshigoto no jikan", "group:osouzaiya-san", "group:osova", @@ -4439,6 +4485,7 @@ object Group : TagList { "group:pockyfactory", "group:poco black", "group:poco poco", + "group:poino", "group:poisonblues", "group:poiyo dimension", "group:pokachutei", @@ -4464,6 +4511,7 @@ object Group : TagList { "group:poppin stompin", "group:popship", "group:popularplus", + "group:porcini", "group:porno maker", "group:potato house", "group:poteto dango", @@ -4544,7 +4592,6 @@ object Group : TagList { "group:rabbit kuukan", "group:rabbits", "group:rabitan", - "group:rabu.", "group:raccoondog", "group:radiant slash h plus", "group:radiostar", @@ -4797,6 +4844,7 @@ object Group : TagList { "group:sakura mangekyou", "group:sakura naomiki", "group:sakura nigou", + "group:sakura no tomoru hie", "group:sakura prin", "group:sakura zensen", "group:sakuradou", @@ -4827,6 +4875,7 @@ object Group : TagList { "group:sangenshokudou", "group:sanjuuhachi shiki kikanjuu", "group:sankaku apron", + "group:sankaku button", "group:sankaku doumei", "group:sankokudo", "group:sanma kizoku", @@ -5081,6 +5130,7 @@ object Group : TagList { "group:shonen gekikuukan", "group:shonnaka-dou", "group:shootouts", + "group:short kami", "group:shortcut koubou", "group:shosekido", "group:shouchuu mac", @@ -5110,6 +5160,7 @@ object Group : TagList { "group:shuryousha", "group:shuto reccara", "group:shuueisha", + "group:shuukyuu 8-ka", "group:shuukyuu itsukasei", "group:shuutaisei", "group:shyness over drive", @@ -5143,9 +5194,9 @@ object Group : TagList { "group:siop", "group:sioyaki", "group:sioyude", + "group:sirisiri denbu club", "group:sirius soft", "group:siro house", - "group:siropome", "group:sirouto plan", "group:sirubedou", "group:sisinabeya", @@ -5261,6 +5312,7 @@ object Group : TagList { "group:st. rio", "group:st. rororo", "group:staccato squirrel", + "group:stamina teishoku", "group:standard azarashi", "group:star link", "group:star-dreamer tei", @@ -5402,7 +5454,6 @@ object Group : TagList { "group:sushi-go-round", "group:suteinu nursery", "group:sutekiplan", - "group:suzuki masahisa", "group:suzuki shouten", "group:suzunaridou", "group:suzupony", @@ -5421,6 +5472,7 @@ object Group : TagList { "group:syamisen koubou", "group:synthetic garden", "group:syonen-kikakugai.", + "group:syounan rakujin society", "group:syounen heroine", "group:syounen kouraku", "group:syouseki kessyou", @@ -5474,6 +5526,7 @@ object Group : TagList { "group:takara no suzunari", "group:takashi-ya", "group:takayashiki kaihatsu", + "group:take4 project", "group:takeda syouten", "group:takegamiya", "group:takeshidou-chou", @@ -5494,6 +5547,7 @@ object Group : TagList { "group:tamatamasanmyaku", "group:tamokuteki hall", "group:tamokuteki kuukan", + "group:tanajou", "group:tanaka shouten", "group:tanaura honpo", "group:tanetsuke ichinengo", @@ -5526,6 +5580,7 @@ object Group : TagList { "group:team tanabe", "group:team z and 3n", "group:team zero", + "group:team4000", "group:tears of ymir", "group:teatime", "group:tecchitecchi", @@ -5534,9 +5589,11 @@ object Group : TagList { "group:tedaingu", "group:teddy-plaza", "group:teemonk", + "group:teiesuya", "group:teihatu syouzyo titai", "group:teikiatu de ikou", "group:teikoku club", + "group:tekirororock", "group:tekken neko gourmet", "group:tekoman-dou", "group:telomere limiter", @@ -5718,6 +5775,7 @@ object Group : TagList { "group:toumei tsuushin", "group:toushi ryoku kenkyuujo", "group:toutaku tuyagadou", + "group:touyou bujutsu gakkou", "group:touyu okiba kari", "group:touyu stand", "group:touzoku tachi no rakuda no mure", @@ -5918,6 +5976,7 @@ object Group : TagList { "group:usagi youjinbou", "group:usagijiru", "group:usagikoara", + "group:usaginoheya", "group:usagitei", "group:usako kf", "group:usamimi syndrome", @@ -5949,337 +6008,5 @@ object Group : TagList { "group:vagina dentata", "group:valiant", "group:valkyria", - "group:valkyrieharlem", - "group:vanilla fuumi shoujo", - "group:vanilla star", - "group:vanilla-dou max", - "group:variety pot", - "group:vashadow", - "group:vc productions", - "group:venom", - "group:veronica no ha", - "group:violence asia team", - "group:visual biscuits", - "group:vitamin gohan", - "group:vitamin soft", - "group:vitamin x", - "group:vivi-sectr", - "group:vivid color", - "group:vivid dot", - "group:vivido", - "group:viweb", - "group:voltcompany.", - "group:vpans extasy", - "group:vulcannu", - "group:w at nd", - "group:wabi sabi wasabi", - "group:wagamama dou", - "group:wakaba syokei", - "group:wakarase seisaku iinkai", - "group:wakatobi", - "group:wakusei-teki shukou", - "group:wakuwaku boycott", - "group:wakuwaku doubutsuen", - "group:walhalla illusion", - "group:wamusho", - "group:wanko-tei", - "group:wankyoku canvas", - "group:wanwandoh", - "group:warabimochi", - "group:waretama", - "group:warp loop", - "group:washikul.", - "group:washokudeniku.", - "group:wata 120 percent", - "group:wataame", - "group:watagashi maker", - "group:watanabe tou", - "group:wataru kuya", - "group:water ducts", - "group:waterfall", - "group:waterspoon", - "group:waterstudio", - "group:waterwheel", - "group:weather report", - "group:webstudioofflimits", - "group:wellca", - "group:wendybell", - "group:west vision", - "group:whirl-wind", - "group:white out", - "group:white plus dk", - "group:white rocket", - ) - - override fun getTags4() = listOf( - "group:whitecloth", - "group:whitesoft", - "group:whitewill", - "group:wi-fe hacker", - "group:wicked heart", - "group:wild goat", - "group:will tame", - "group:willow soft", - "group:wind mail", - "group:wind of the keep valley", - "group:windarteam", - "group:winger in mind", - "group:winghills", - "group:wish", - "group:wish kibou no tsubasa", - "group:witchflame", - "group:witching hour entertainment", - "group:wizard", - "group:wolf fang dou", - "group:wonderland 203", - "group:wope-retta", - "group:world of porncraft", - "group:world temperament", - "group:worstworks", - "group:wriggle souzeme tomonokai", - "group:x model", - "group:x-tei", - "group:xephs artwork", - "group:xl-toons", - "group:xx koubou", - "group:xxxxxxx", - "group:xyzyroh", - "group:y slash s slash k", - "group:y.d.l", - "group:y.m.sensha", - "group:yaboudo project", - "group:yabougumi", - "group:yabukaradou", - "group:yaburi dokoro", - "group:yadapot", - "group:yadokugaeru", - "group:yadoo van yahdoo", - "group:yagi q-syah", - "group:yago no ana", - "group:yajilshi plus", - "group:yajirushi key", - "group:yajiya", - "group:yakata", - "group:yakimisomura", - "group:yakinasu teishoku", - "group:yakiniku teishoku", - "group:yakisaketeishoku", - "group:yakisoba pants", - "group:yakisoba rengo", - "group:yakiubu", - "group:yakousei fan club", - "group:yaku 40 man sarad", - "group:yakumi sarai", - "group:yakusyo", - "group:yakutai", - "group:yam x 2 dai teikoku", - "group:yamada ichizoku.", - "group:yamadamaya", - "group:yamadaya", - "group:yamagiwa art cg studio", - "group:yamaguchirou", - "group:yamakawa denenhuukei", - "group:yamami no yado", - "group:yamamori gohan", - "group:yamanaka no naka", - "group:yamano murao", - "group:yami ni ugomeku", - "group:yamikumo tsuushin", - "group:yamotodou rakugakiichi", - "group:yanagiba dai", - "group:yanagisegawa", - "group:yanasegawabeya", - "group:yangyang nickbow", - "group:yanmarumaa", - "group:yaou keikaku", - "group:yaoyorozu-kobo", - "group:yaoyorozudo", - "group:yasai batake", - "group:yaseuma lo-ru", - "group:yashiya", - "group:yashock kaigi", - "group:yasrin-do", - "group:yasudajuku", - "group:yasuomi-craft", - "group:yasyokutei", - "group:yatuumi no kagami", - "group:yawaraka okashiya", - "group:yaya hinata-ya", - "group:yes sir.", - "group:yggdrasil", - "group:yo-metdo", - "group:yoban left", - "group:yobigakka", - "group:yohsyuan", - "group:yojouhan factory", - "group:yojouhan shobou", - "group:yojouhan toshi", - "group:yokan musume", - "group:yokazetei", - "group:yokohama zza koubou", - "group:yokoshimanchi.", - "group:yokoshimaya", - "group:yokoshoku ice", - "group:yomamagoto", - "group:yomosue doukoukai", - "group:yomothuhirasaka", - "group:yonatan black mutou", - "group:yonbangai garo", - "group:yonjuichi", - "group:yonmasuya", - "group:yonurime", - "group:yorando", - "group:yoru no benkyoukai", - "group:yoru no okazu shokudou", - "group:yoruyama no kyuukeijo", - "group:yoseatume tekina nanika", - "group:yoshida gorou shoukai", - "group:yoshiga dokoro", - "group:yoshii tech sha", - "group:yotukuro", - "group:you", - "group:you you tsuushin", - "group:you you you", - "group:youchi-na-ochakai", - "group:youen bijo no garou", - "group:youkai ankake", - "group:youkai tamanokoshi", - "group:youkandou", - "group:youki m.k.c.", - "group:youmusya", - "group:yours-wow", - "group:yousei allergen", - "group:youseimangasya", - "group:youtoujirushi", - "group:youtsuu transmitter", - "group:youyukai", - "group:yowatari kouba", - "group:yoyude ikemasu", - "group:yozorairodrops", - "group:ys company", - "group:yu-ta.18", - "group:yu-yu-tei", - "group:yuasa rengou", - "group:yubidou", - "group:yudenakya nama-beer", - "group:yudokuya", - "group:yuhshiki", - "group:yukagenikaga", - "group:yukeyuke ryuseigo", - "group:yuki daruma koujou", - "group:yuki no iori", - "group:yukijirushi nyuugyou", - "group:yukikagerou", - "group:yukimi honpo", - "group:yukimura", - "group:yukinko okeya", - "group:yukino koubou", - "group:yukirinrin", - "group:yukyu-kyuka", - "group:yume bouei shoujo tai", - "group:yume yori suteki na", - "group:yume-zakura", - "group:yumeiro-goromo", - "group:yumeizukosya", - "group:yumemigachi campus", - "group:yumemigokoti", - "group:yumemiru-kikai", - "group:yumenamakon", - "group:yumenokage", - "group:yumeoikyounouta", - "group:yumeoukoku", - "group:yunabon", - "group:yurayuraseyuura", - "group:yureika blade", - "group:yuri dokidoki", - "group:yuri equal 18l", - "group:yuriai kojinshi kai", - "group:yurinyurin", - "group:yuriru-rarika", - "group:yurumebox", - "group:yuruyakatou", - "group:yuruyuru seisakusho", - "group:yusuzumi", - "group:yuu adashino suisan", - "group:yuu heya", - "group:yuubin basha", - "group:yuudachitei", - "group:yuuendou", - "group:yuugai tosho kikaku", - "group:yuugen kaisha sokuhou seisakusho", - "group:yuugensangyou sukimakaze", - "group:yuugure koubou", - "group:yuuhodou", - "group:yuujikouji", - "group:yuukakumin", - "group:yuuki kagoubutsu", - "group:yuukyuu shinden", - "group:yuukyuu suisenkan", - "group:yuunagi gaibutai", - "group:yuuriko", - "group:yuusha kandenchi", - "group:yuutopia", - "group:yuuya-yuu", - "group:yuyake box", - "group:yuzu soft", - "group:yuzucha", - "group:yuzuen", - "group:yuzumomo jam", - "group:yuzuonsen", - "group:yuzuponz", - "group:yuzurihaya", - "group:z", - "group:z-tabukuroneko house", - "group:z-vector", - "group:za da carjya", - "group:zakkin kougyou", - "group:zan-sei", - "group:zankirow", - "group:zankoku doumei", - "group:zankoku na kami ga shihai suru", - "group:zantetuken", - "group:zasshu-ken", - "group:zassoubatake", - "group:zassoya", - "group:zatouichi", - "group:zatuyou gakari", - "group:zawameki jambo", - "group:zeiniku shoujotai", - "group:zenmai koubou", - "group:zenmai kourogi", - "group:zennihon do-m jitsuryoku kentei kousa", - "group:zenoside", - "group:zenra restaurant", - "group:zensekai yakenohara doumei", - "group:zenshuu bougyo", - "group:zensoku zenkai.", - "group:zensun habaku", - "group:zenzidou kosyubenjo", - "group:zero byte", - "group:zero equals mono", - "group:zero ni kaeru tsuki", - "group:zero-one", - "group:zero-sen", - "group:zero-xx", - "group:zerocool", - "group:zeroinfinityone", - "group:zeryishi", - "group:zettai shoujo", - "group:zettaitensei", - "group:zgf", - "group:zi", - "group:zion", - "group:zmey no soukutsu", - "group:zokubutsu.zip", - "group:zombie to yukaina nakamatachi", - "group:zonzon sharp 4", - "group:zooerastia", - "group:zouri no sato", - "group:zozalist", - "group:zugaikotsu marudashi", - "group:zvizva-dan", - "group:zydan", - "group:zyulokuya", - "group:zzz comics", ) } diff --git a/app/src/main/java/exh/eh/tags/Group2.kt b/app/src/main/java/exh/eh/tags/Group2.kt new file mode 100644 index 000000000..92728c5d8 --- /dev/null +++ b/app/src/main/java/exh/eh/tags/Group2.kt @@ -0,0 +1,342 @@ +package exh.eh.tags + +object Group2 : TagList { + override fun getTags1(): List = listOf( + "group:valkyrieharlem", + "group:vanilla fuumi shoujo", + "group:vanilla star", + "group:vanilla-dou max", + "group:variety pot", + "group:vashadow", + "group:vc productions", + "group:venom", + "group:veronica no ha", + "group:violence asia team", + "group:visual biscuits", + "group:vitamin gohan", + "group:vitamin soft", + "group:vitamin x", + "group:vivi-sectr", + "group:vivid color", + "group:vivid dot", + "group:vivido", + "group:viweb", + "group:voltcompany.", + "group:vpans extasy", + "group:vulcannu", + "group:w at nd", + "group:wabi sabi wasabi", + "group:wagamama dou", + "group:wakaba syokei", + "group:wakarase seisaku iinkai", + "group:wakatobi", + "group:wakusei-teki shukou", + "group:wakuwaku boycott", + "group:wakuwaku doubutsuen", + "group:walhalla illusion", + "group:wamusho", + "group:wanko-tei", + "group:wankyoku canvas", + "group:wanwandoh", + "group:warabimochi", + "group:waretama", + "group:warp loop", + "group:wasa wasa", + "group:washikul.", + "group:washokudeniku.", + "group:wata 120 percent", + "group:wataame", + "group:watagashi maker", + "group:watanabe tou", + "group:wataru kuya", + "group:water ducts", + "group:waterfall", + "group:waterspoon", + "group:waterstudio", + "group:waterwheel", + "group:weather report", + "group:webstudioofflimits", + "group:wellca", + "group:wendybell", + "group:west vision", + "group:whirl-wind", + "group:white out", + "group:white plus dk", + "group:white rocket", + "group:whitecloth", + "group:whitesoft", + "group:whitewill", + "group:wi-fe hacker", + "group:wicked heart", + "group:wild goat", + "group:will tame", + "group:willow soft", + "group:wind mail", + "group:wind of the keep valley", + "group:windarteam", + "group:winger in mind", + "group:winghills", + "group:wish", + "group:wish kibou no tsubasa", + "group:witchflame", + "group:witching hour entertainment", + "group:wizard", + "group:wolf fang dou", + "group:wonderland 203", + "group:wope-retta", + "group:world of porncraft", + "group:world temperament", + "group:worstworks", + "group:wriggle souzeme tomonokai", + "group:x model", + "group:x-tei", + "group:xephs artwork", + "group:xl-toons", + "group:xx koubou", + "group:xxxxxxx", + "group:xyzyroh", + "group:y slash s slash k", + "group:y.d.l", + "group:y.m.sensha", + "group:yaboudo project", + "group:yabougumi", + "group:yabukaradou", + "group:yaburi dokoro", + "group:yadapot", + "group:yadokugaeru", + "group:yadoo van yahdoo", + "group:yagi q-syah", + "group:yago no ana", + "group:yajilshi plus", + "group:yajirushi key", + "group:yajiya", + "group:yakata", + "group:yakimisomura", + "group:yakinasu teishoku", + "group:yakiniku teishoku", + "group:yakisaketeishoku", + "group:yakisoba pants", + "group:yakisoba rengo", + "group:yakiubu", + "group:yakousei fan club", + "group:yaku 40 man sarad", + "group:yakumi sarai", + "group:yakusyo", + "group:yakutai", + "group:yam x 2 dai teikoku", + "group:yamada ichizoku.", + "group:yamadamaya", + "group:yamadaya", + "group:yamagiwa art cg studio", + "group:yamaguchirou", + "group:yamakawa denenhuukei", + "group:yamami no yado", + "group:yamamori gohan", + "group:yamanaka no naka", + "group:yamano murao", + "group:yamato nadeshiko club", + "group:yami ni ugomeku", + "group:yamikumo tsuushin", + "group:yamotodou rakugakiichi", + "group:yanagiba dai", + "group:yanagisegawa", + "group:yanasegawabeya", + "group:yangyang nickbow", + "group:yanmarumaa", + "group:yaou keikaku", + "group:yaoyorozu-kobo", + "group:yaoyorozudo", + "group:yasai batake", + "group:yaseuma lo-ru", + "group:yashiya", + "group:yashock kaigi", + "group:yasrin-do", + "group:yasudajuku", + "group:yasuomi-craft", + "group:yasyokutei", + "group:yatomomin", + "group:yatuumi no kagami", + "group:yawaraka okashiya", + "group:yaya hinata-ya", + "group:yes sir.", + "group:yggdrasil", + "group:yo-metdo", + "group:yoban left", + "group:yobigakka", + "group:yohsyuan", + "group:yojouhan factory", + "group:yojouhan shobou", + "group:yojouhan toshi", + "group:yokan musume", + "group:yokazetei", + "group:yokohama zza koubou", + "group:yokoshimanchi.", + "group:yokoshimaya", + "group:yokoshoku ice", + "group:yoku mireba beta", + "group:yomamagoto", + "group:yomosue doukoukai", + "group:yomothuhirasaka", + "group:yonatan black mutou", + "group:yonbangai garo", + "group:yonjuichi", + "group:yonmasuya", + "group:yonurime", + "group:yorando", + "group:yoru no benkyoukai", + "group:yoru no okazu shokudou", + "group:yoruyama no kyuukeijo", + "group:yoseatume tekina nanika", + "group:yoshida gorou shoukai", + "group:yoshiga dokoro", + "group:yoshii tech sha", + "group:yotukuro", + "group:you", + "group:you you tsuushin", + "group:you you you", + "group:youchi-na-ochakai", + "group:youen bijo no garou", + "group:yougensya", + "group:youkai ankake", + "group:youkai tamanokoshi", + "group:youkandou", + "group:youki m.k.c.", + "group:youmusya", + "group:yours-wow", + "group:yousei allergen", + "group:youseimangasya", + "group:youtoujirushi", + "group:youtsuu transmitter", + "group:youyukai", + "group:yowatari kouba", + "group:yoyude ikemasu", + "group:yozorairodrops", + "group:ys company", + "group:yu-ta.18", + "group:yu-yu-tei", + "group:yuasa rengou", + "group:yubidou", + "group:yudenakya nama-beer", + "group:yudokuya", + "group:yuhshiki", + "group:yukagenikaga", + "group:yukan high zakura", + "group:yukeyuke ryuseigo", + "group:yuki daruma koujou", + "group:yuki no iori", + "group:yukijirushi nyuugyou", + "group:yukikagerou", + "group:yukimi honpo", + "group:yukimura", + "group:yukinko okeya", + "group:yukino koubou", + "group:yukirinrin", + "group:yukyu-kyuka", + "group:yume bouei shoujo tai", + "group:yume yori suteki na", + "group:yume-zakura", + "group:yumeiro-goromo", + "group:yumeizukosya", + "group:yumemigachi campus", + "group:yumemigokoti", + "group:yumemiru-kikai", + "group:yumenamakon", + "group:yumenokage", + "group:yumeoikyounouta", + "group:yumeoukoku", + "group:yunabon", + "group:yurayuraseyuura", + "group:yureika blade", + "group:yuri dokidoki", + "group:yuri equal 18l", + "group:yuriai kojinshi kai", + "group:yurinyurin", + "group:yuriru-rarika", + "group:yurumebox", + "group:yuruyakatou", + "group:yuruyuru seisakusho", + "group:yusuzumi", + "group:yuu adashino suisan", + "group:yuu heya", + "group:yuubin basha", + "group:yuudachitei", + "group:yuuendou", + "group:yuugai tosho kikaku", + "group:yuugen kaisha sokuhou seisakusho", + "group:yuugensangyou sukimakaze", + "group:yuugure koubou", + "group:yuuhodou", + "group:yuujikouji", + "group:yuukakumin", + "group:yuuki kagoubutsu", + "group:yuukyuu shinden", + "group:yuukyuu suisenkan", + "group:yuunagi gaibutai", + "group:yuuriko", + "group:yuusha kandenchi", + "group:yuutopia", + "group:yuuya-yuu", + "group:yuyake box", + "group:yuzu soft", + "group:yuzucha", + "group:yuzuen", + "group:yuzumomo jam", + "group:yuzuonsen", + "group:yuzuponz", + "group:yuzurihaya", + "group:z", + "group:z-tabukuroneko house", + "group:z-vector", + "group:za da carjya", + "group:zakkin kougyou", + "group:zan-sei", + "group:zankirow", + "group:zankoku doumei", + "group:zankoku na kami ga shihai suru", + "group:zantetuken", + "group:zasshu-ken", + "group:zassoubatake", + "group:zassoya", + "group:zatouichi", + "group:zatuyou gakari", + "group:zawameki jambo", + "group:zeiniku shoujotai", + "group:zenmai koubou", + "group:zenmai kourogi", + "group:zennihon do-m jitsuryoku kentei kousa", + "group:zenoside", + "group:zenra restaurant", + "group:zenryoku sissou cat", + "group:zensekai yakenohara doumei", + "group:zenshuu bougyo", + "group:zensoku zenkai.", + "group:zensun habaku", + "group:zenzidou kosyubenjo", + "group:zero byte", + "group:zero equals mono", + "group:zero ni kaeru tsuki", + "group:zero-one", + "group:zero-sen", + "group:zero-xx", + "group:zerocool", + "group:zeroinfinityone", + "group:zeryishi", + "group:zettai shoujo", + "group:zettaitensei", + "group:zgf", + "group:zi", + "group:zion", + "group:zmey no soukutsu", + "group:zokubutsu.zip", + "group:zombie to yukaina nakamatachi", + "group:zonzon sharp 4", + "group:zooerastia", + "group:zouri no sato", + "group:zozalist", + "group:zugaikotsu marudashi", + "group:zvizva-dan", + "group:zydan", + "group:zyulokuya", + "group:zzz comics", + ) +} diff --git a/app/src/main/java/exh/eh/tags/Language.kt b/app/src/main/java/exh/eh/tags/Language.kt index cb1b96998..c2c0bbf45 100644 --- a/app/src/main/java/exh/eh/tags/Language.kt +++ b/app/src/main/java/exh/eh/tags/Language.kt @@ -1,7 +1,7 @@ package exh.eh.tags object Language : TagList { - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( "language:arabic", "language:bulgarian", "language:catalan", diff --git a/app/src/main/java/exh/eh/tags/Male.kt b/app/src/main/java/exh/eh/tags/Male.kt index 7d365b5f1..ce3a1ff5e 100644 --- a/app/src/main/java/exh/eh/tags/Male.kt +++ b/app/src/main/java/exh/eh/tags/Male.kt @@ -1,28 +1,39 @@ package exh.eh.tags object Male : TagList { - - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( "male:abortion", "male:absorption", + "male:adventitious penis", + "male:afro", "male:age progression", "male:age regression", "male:ahegao", + "male:albino", "male:alien", + "male:all the way through", "male:amputee", "male:anal", "male:anal birth", "male:anal intercourse", "male:anal prolapse", + "male:analphagia", "male:angel", + "male:animal on animal", "male:animal on furry", "male:animegao", + "male:anorexic", "male:apparel bukkake", "male:apron", "male:armpit licking", + "male:armpit sex", "male:asphyxiation", + "male:ass expansion", + "male:assjob", + "male:autofellatio", "male:bald", "male:ball sucking", + "male:balljob", "male:balls expansion", "male:bandages", "male:bat boy", @@ -30,10 +41,14 @@ object Male : TagList { "male:bdsm", "male:bear", "male:bear boy", + "male:beauty mark", "male:bestiality", + "male:big areolae", "male:big ass", "male:big balls", "male:big breasts", + "male:big lips", + "male:big muscles", "male:big nipples", "male:big penis", "male:bike shorts", @@ -47,12 +62,16 @@ object Male : TagList { "male:bloomers", "male:blowjob", "male:blowjob face", + "male:body modification", "male:body painting", "male:body swap", "male:body writing", "male:bodystocking", "male:bodysuit", "male:bondage", + "male:braces", + "male:brain fuck", + "male:breast expansion", "male:breast feeding", "male:bride", "male:brother", @@ -62,11 +81,13 @@ object Male : TagList { "male:burping", "male:business suit", "male:butler", + "male:camel", "male:cannibalism", "male:cashier", "male:cat", "male:catboy", "male:cbt", + "male:centaur", "male:cervix prolapse", "male:chastity belt", "male:cheating", @@ -75,13 +96,20 @@ object Male : TagList { "male:chinese dress", "male:chloroform", "male:christmas", + "male:clamp", + "male:clit insertion", "male:clit stimulation", "male:clone", + "male:closed eyes", "male:clothed female nude male", + "male:clown", "male:coach", "male:cock ring", + "male:cockphagia", + "male:cockslapping", "male:collar", "male:condom", + "male:conjoined", "male:coprophagia", "male:corruption", "male:corset", @@ -90,25 +118,39 @@ object Male : TagList { "male:cowman", "male:crab", "male:crossdressing", + "male:crotch tattoo", "male:crown", + "male:crying", + "male:cum bath", + "male:cumflation", + "male:cunnilingus", "male:cuntboy", "male:dark nipples", "male:dark sclera", "male:dark skin", "male:deepthroat", "male:deer", + "male:deer boy", "male:demon", + "male:denki anma", + "male:detached sleeves", + "male:diaper", "male:dick growth", "male:dickgirl on male", + "male:dicknipples", "male:dilf", "male:dinosaur", "male:dog", "male:dog boy", + "male:doll joints", + "male:dolphin", + "male:domination loss", "male:donkey", "male:double anal", "male:double blowjob", "male:double penetration", "male:dougi", + "male:draenei", "male:dragon", "male:drill hair", "male:drugs", @@ -126,6 +168,7 @@ object Male : TagList { "male:eye-covering bang", "male:eyemask", "male:eyepatch", + "male:facesitting", "male:facial hair", "male:fairy", "male:farting", @@ -138,8 +181,10 @@ object Male : TagList { "male:fisting", "male:focus paizuri", "male:food on body", + "male:foot insertion", "male:foot licking", "male:footjob", + "male:forced exposure", "male:forniphilia", "male:fox", "male:fox boy", @@ -156,8 +201,13 @@ object Male : TagList { "male:gender morph", "male:ghost", "male:giant", + "male:giant sperm", + "male:gijinka", + "male:giraffe boy", "male:glasses", "male:glory hole", + "male:gloves", + "male:goat", "male:goblin", "male:gokkun", "male:gorilla", @@ -169,42 +219,63 @@ object Male : TagList { "male:gyaru-oh", "male:gymshorts", "male:hair buns", + "male:hairjob", "male:hairy", + "male:hairy armpits", "male:handjob", + "male:hanging", "male:harem", "male:harpy", "male:headphones", + "male:heterochromia", + "male:hijab", + "male:hood", "male:horns", "male:horse", "male:horse boy", "male:horse cock", "male:hotpants", + "male:huge penis", "male:human on furry", "male:humiliation", + "male:hyena boy", "male:impregnation", "male:incest", "male:infantilism", "male:inflation", "male:insect", "male:insect boy", + "male:internal urination", + "male:inverted nipples", "male:invisible", "male:josou seme", + "male:kangaroo", + "male:kappa", "male:kemonomimi", "male:kigurumi pajama", "male:kimono", + "male:kindergarten uniform", "male:kissing", + "male:kunoichi", "male:lab coat", + "male:lactation", "male:large insertions", "male:large tattoo", "male:latex", "male:layer cake", + "male:leash", + "male:leg lock", "male:leotard", "male:lingerie", "male:lion", + "male:living clothes", "male:lizard guy", "male:long tongue", "male:low bestiality", + "male:low guro", + "male:low scat", "male:low shotacon", + "male:low smegma", "male:machine", "male:maggot", "male:magical girl", @@ -213,33 +284,46 @@ object Male : TagList { "male:males only", "male:masked face", "male:masturbation", + "male:mecha boy", "male:merman", "male:mesuiki", "male:metal armor", "male:midget", "male:miko", "male:military", + "male:milking", "male:mind break", "male:mind control", "male:miniguy", "male:minotaur", + "male:mmm threesome", "male:monkey", "male:monkey boy", + "male:monoeye", "male:monster", "male:moral degeneration", "male:mouse", "male:mouse boy", + "male:mouth mask", + "male:multimouth blowjob", + "male:multiple arms", "male:multiple assjob", "male:multiple footjob", "male:multiple handjob", "male:multiple orgasms", "male:multiple penises", + "male:multiple straddling", "male:muscle", + "male:muscle growth", "male:nakadashi", + "male:navel fuck", + "male:nazi", "male:necrophilia", "male:netorare", "male:ninja", "male:nipple birth", + "male:nipple fuck", + "male:nipple stimulation", "male:nose fuck", "male:nose hook", "male:nun", @@ -248,94 +332,131 @@ object Male : TagList { "male:oil", "male:old man", "male:onahole", + "male:oni", "male:orc", "male:orgasm denial", + "male:ostrich", "male:otokofutanari", + "male:otter boy", + "male:oyakodon", "male:paizuri", + "male:panda boy", "male:panther", "male:pantyhose", + "male:pantyjob", + "male:parasite", "male:pasties", + "male:pegasus", "male:pegging", "male:penis birth", + "male:personality excretion", "male:petplay", + "male:petrification", "male:phimosis", "male:piercing", "male:pig", "male:pig man", "male:pillory", + "male:pirate", "male:piss drinking", + "male:pixie cut", "male:plant boy", "male:pole dancing", "male:policeman", + "male:ponytail", "male:possession", "male:pregnant", + "male:prehensile hair", "male:priest", "male:prolapse", "male:prostate massage", "male:prostitution", "male:pubic stubble", "male:public use", + "male:pussyboys only", "male:rabbit", + "male:raccoon boy", "male:randoseru", "male:rape", "male:reptile", + "male:retractable penis", "male:rhinoceros", "male:rimjob", "male:robot", "male:ryona", + "male:saliva", "male:scar", "male:scat", "male:school gym uniform", "male:school swimsuit", "male:schoolboy uniform", "male:schoolgirl uniform", + "male:scrotal lingerie", "male:selfcest", "male:sex toys", "male:shared senses", "male:shark", "male:shark boy", + "male:shaved head", "male:sheep", "male:sheep boy", "male:shibari", + "male:shimaidon", "male:shimapan", "male:shotacon", "male:shrinking", "male:skinsuit", + "male:skunk boy", "male:slave", "male:sleeping", "male:slime", "male:slime boy", "male:slug", "male:small penis", + "male:smalldom", "male:smegma", "male:smell", "male:smoking", "male:snake", "male:snake boy", "male:snuff", + "male:sockjob", "male:sole male", + "male:sole pussyboy", "male:solo action", "male:spanking", "male:speculum", "male:spider", + "male:spider boy", "male:squid boy", + "male:squirrel boy", + "male:ssbbm", + "male:steward", "male:stewardess", + "male:stirrup legwear", "male:stockings", "male:stomach deformation", + "male:straitjacket", + "male:strap-on", "male:stretching", "male:stuck in wall", + "male:sumata", "male:sundress", "male:sunglasses", "male:sweating", "male:swimsuit", "male:swinging", "male:syringe", + "male:table masturbation", "male:tail", "male:tail plug", + "male:tailjob", + "male:tailphagia", "male:tall man", "male:tanlines", "male:teacher", "male:tentacles", + "male:thick eyebrows", "male:thigh high boots", "male:tiara", "male:tickling", @@ -348,16 +469,23 @@ object Male : TagList { "male:tracksuit", "male:trampling", "male:transformation", + "male:triple anal", + "male:triple penetration", "male:tube", "male:turtle", "male:tutor", "male:twins", + "male:twintails", "male:unbirth", "male:uncle", + "male:underwater", "male:unicorn", + "male:unusual insertions", "male:unusual pupils", + "male:unusual teeth", "male:urethra insertion", "male:urination", + "male:vacbed", "male:vampire", "male:very long hair", "male:virginity", @@ -366,6 +494,9 @@ object Male : TagList { "male:voyeurism", "male:waiter", "male:waitress", + "male:weight gain", + "male:wet clothes", + "male:whale", "male:whip", "male:wings", "male:witch", @@ -374,8 +505,11 @@ object Male : TagList { "male:wooden horse", "male:worm", "male:wormhole", + "male:wrestling", "male:x-ray", "male:yandere", "male:yaoi", + "male:zebra", + "male:zombie", ) } diff --git a/app/src/main/java/exh/eh/tags/Mixed.kt b/app/src/main/java/exh/eh/tags/Mixed.kt index 47e670a6c..01911e33d 100644 --- a/app/src/main/java/exh/eh/tags/Mixed.kt +++ b/app/src/main/java/exh/eh/tags/Mixed.kt @@ -1,8 +1,7 @@ package exh.eh.tags object Mixed : TagList { - - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( "mixed:animal on animal", "mixed:body swap", "mixed:ffm threesome", @@ -16,6 +15,7 @@ object Mixed : TagList { "mixed:multiple assjob", "mixed:multiple footjob", "mixed:multiple handjob", + "mixed:nudism", "mixed:oyakodon", "mixed:shimaidon", "mixed:ttm threesome", diff --git a/app/src/main/java/exh/eh/tags/Other.kt b/app/src/main/java/exh/eh/tags/Other.kt index 2edbd2f67..a4b188d8a 100644 --- a/app/src/main/java/exh/eh/tags/Other.kt +++ b/app/src/main/java/exh/eh/tags/Other.kt @@ -1,9 +1,9 @@ package exh.eh.tags object Other : TagList { - - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( "other:3d", + "other:3d imageset", "other:already uploaded", "other:anaglyph", "other:animated", @@ -13,10 +13,12 @@ object Other : TagList { "other:comic", "other:compilation", "other:dakimakura", + "other:defaced", "other:figure", "other:forbidden content", "other:full censorship", "other:full color", + "other:game manual", "other:game sprite", "other:goudoushi", "other:hardcore", @@ -33,10 +35,10 @@ object Other : TagList { "other:nudity only", "other:out of order", "other:paperchild", - "other:poor grammar", "other:realporn", "other:redraw", "other:replaced", + "other:rough grammar", "other:rough translation", "other:sample", "other:scanmark", diff --git a/app/src/main/java/exh/eh/tags/Parody.kt b/app/src/main/java/exh/eh/tags/Parody.kt index aca54d1c2..6eb224dfd 100644 --- a/app/src/main/java/exh/eh/tags/Parody.kt +++ b/app/src/main/java/exh/eh/tags/Parody.kt @@ -1,7 +1,7 @@ package exh.eh.tags object Parody : TagList { - override fun getTags1() = listOf( + override fun getTags1(): List = listOf( "parody:.hack", "parody:.hackg.u.", "parody:.hacklegend of the twilight", @@ -31,6 +31,7 @@ object Parody : TagList { "parody:a town where you live", "parody:a vampyre story", "parody:a.d.police", + "parody:a.i. ga tomaranai", "parody:abenobashi mahou shoutengai", "parody:acca 13-ku kansatsu-ka", "parody:accel world", @@ -66,8 +67,10 @@ object Parody : TagList { "parody:akira", "parody:aku no musume", "parody:aku no onna kanbu", + "parody:akuma no memumemu-chan", "parody:akuyaku reijou nanode last boss o kattemimashita", "parody:aladdin", + "parody:albatross koukairoku", "parody:aldnoah.zero", "parody:alice gear aegis", "parody:alice in wonderland", @@ -124,6 +127,7 @@ object Parody : TagList { "parody:ar nosurge", "parody:ar tonelico", "parody:ar tonelico qoga", + "parody:araburu kisetsu no otome-domo yo", "parody:araiguma rascal", "parody:arasaa mama no watashi de ii no", "parody:arcana famiglia", @@ -194,6 +198,7 @@ object Parody : TagList { "parody:backbeard-sama ga miteru", "parody:bagi the monster of mighty nature", "parody:baka to test to shoukanjuu", + "parody:bakemono no ko", "parody:bakemonogatari", "parody:bakuen campus guardress", "parody:bakugan", @@ -206,6 +211,7 @@ object Parody : TagList { "parody:ballroom e youkoso", "parody:bamboo blade", "parody:band yarouze", + "parody:banished from the heros party i decided to live a quiet life in the countryside", "parody:banjo-kazooie", "parody:banner of the stars", "parody:baribari densetsu", @@ -271,6 +277,7 @@ object Parody : TagList { "parody:bloodstained", "parody:bloody roar", "parody:blue dragon", + "parody:blue skin no mori", "parody:blue spring ride", "parody:blue submarine no. 6", "parody:bna brand new animal", @@ -355,6 +362,7 @@ object Parody : TagList { "parody:childs play", "parody:chio-chan no tsuugakuro", "parody:chip n dale rescue rangers", + "parody:cho aniki", "parody:chobits", "parody:chogattai majutsu robot ginguiser", "parody:chokotto sister", @@ -428,6 +436,7 @@ object Parody : TagList { "parody:daiakuji", "parody:daibanchou -big bang age-", "parody:daicon", + "parody:daihanjou manpuku marche", "parody:daikoukai jidai", "parody:daisenryaku", "parody:daiya no ace", @@ -440,6 +449,7 @@ object Parody : TagList { "parody:dantalian no shoka", "parody:daphne in the brilliant blue", "parody:dark chronicle", + "parody:dark messiah", "parody:dark water", "parody:darker than black", "parody:darkstalkers", @@ -457,6 +467,7 @@ object Parody : TagList { "parody:defenders", "parody:defense devil", "parody:defense of the ancients", + "parody:delicious party precure", "parody:demento", "parody:demi-chan wa kataritai", "parody:demonbane", @@ -480,6 +491,7 @@ object Parody : TagList { "parody:devil may cry", "parody:devil summoner soul hackers", "parody:devil survivor", + "parody:devilman lady", "parody:dexters laboratory", "parody:di gi charat", "parody:diablo", @@ -550,6 +562,7 @@ object Parody : TagList { "parody:dragonaut", "parody:dragonica", "parody:dragons crown", + "parody:dragons raiden", "parody:drakengard", "parody:drawn together", "parody:dream c club", @@ -619,6 +632,7 @@ object Parody : TagList { "parody:family project", "parody:fancy lala", "parody:fantastic four", + "parody:fantasy bishoujo juniku ojisan to", "parody:fantasy earth zero", "parody:far east of eden kabuki klash", "parody:fatal frame", @@ -706,6 +720,7 @@ object Parody : TagList { "parody:fushigi no umi no nadia", "parody:fushigi yuugi", "parody:fushigiboshi no futagohime", + "parody:futaba channel", "parody:futakoi", "parody:futari ecchi", "parody:futari wa precure splash star", @@ -723,6 +738,7 @@ object Parody : TagList { "parody:ga-rei", "parody:gad guard", "parody:gaiking", + "parody:gaikotsu kishi-sama tadaima isekai e odekakechuu", "parody:gakkou gurashi", "parody:gakkou no kaidan", "parody:gakuen alice", @@ -733,6 +749,7 @@ object Parody : TagList { "parody:galaxy cyclone braiger", "parody:galaxy express 999", "parody:galaxy fraulein yuna", + "parody:galleria no chika meikyuu to majo no ryodan", "parody:gan kon", "parody:ganbare goemon", "parody:gangsta.", @@ -753,6 +770,7 @@ object Parody : TagList { "parody:gen 13", "parody:gen colon lock", "parody:genji tsuushin agedama", + "parody:genkai tokki monster monpiece", "parody:genmu no tou to tsurugi no okite", "parody:genmu senki leda", "parody:genroh", @@ -824,6 +842,7 @@ object Parody : TagList { "parody:gundam 00", "parody:gundam 0083", "parody:gundam age", + "parody:gundam breaker mobile", "parody:gundam build fighters", "parody:gundam g no reconguista", "parody:gundam seed", @@ -856,6 +875,7 @@ object Parody : TagList { "parody:hakumei to mikochi", "parody:hakuouki", "parody:hakushaku to yousei", + "parody:hakushon daimaou", "parody:half-life", "parody:halo", "parody:hamtaro", @@ -906,8 +926,10 @@ object Parody : TagList { "parody:highschool dxd", "parody:highschool of the dead", "parody:higurashi no naku koro ni", + "parody:higyaku no noel", "parody:hikarian", "parody:hikaru no go", + "parody:hikounin sentai akibaranger", "parody:hime chen otogi chikku idol lilpri", "parody:hime kishi lilia", "parody:hime-chans ribbon", @@ -918,6 +940,7 @@ object Parody : TagList { "parody:history kikan", "parody:historys strongest disciple kenichi", "parody:hitomi no karte", + "parody:hitomi-chan wa hitomishiri", "parody:hitomi-sensei no hokenshitsu", "parody:hitori bocchi no marumaru seikatsu", "parody:hitsugi katsugi no kuro.", @@ -978,6 +1001,7 @@ object Parody : TagList { "parody:ikoku meiro no croisee", "parody:imouto sae ireba ii.", "parody:in search of the lost future", + "parody:inaka ni kaeru to yakeni natsuita kasshoku ponytail shota ga iru", "parody:inazuma eleven", "parody:inazuman", "parody:inda no himekishi janne", @@ -998,6 +1022,7 @@ object Parody : TagList { "parody:is", "parody:isekai izakaya nobu", "parody:isekai maou to shoukan shoujo no dorei majutsu", + "parody:isekai meikyuu de harem o", "parody:isekai no seikishi monogatari", "parody:isekai shokudou", "parody:isekai wa smartphone to tomo ni.", @@ -1007,6 +1032,7 @@ object Parody : TagList { "parody:its not my fault that im not popular", "parody:iwa kakeru", "parody:ixion saga dt", + "parody:iya na kao sare nagara opantsu misete moraitai", "parody:izuna legend of the unemployed ninja", "parody:jackie chan adventures", "parody:jaja uma grooming up", @@ -1035,9 +1061,11 @@ object Parody : TagList { "parody:johnny bravo", "parody:johnny test", "parody:jojos bizarre adventure", + "parody:joshikousei girls high", "parody:joshikousei no mudazukai", "parody:joukamachi no dandelion", "parody:jouki toshi no tantei shoujo", + "parody:ju-on", "parody:jubei-chan", "parody:jumping rabbit", "parody:jungle de ikou", @@ -1060,11 +1088,13 @@ object Parody : TagList { "parody:k.o. beast", "parody:kaerunyo panyorn", "parody:kage no densetsu", + "parody:kageki shojo", "parody:kagihime monogatari eikyuu alice rondo", "parody:kaguya-sama wa kokurasetai", "parody:kaichou wa maid-sama", "parody:kaifuku jutsushi no yarinaoshi", "parody:kaiji", + "parody:kaijin kaihatsubu no kuroitsu-san", "parody:kaiketsu zorro", "parody:kaitou tenshi twin angel", "parody:kaizoku sentai gokaiger", @@ -1080,6 +1110,7 @@ object Parody : TagList { "parody:kami-tachi ni hirowareta otoko", "parody:kamikaze kaitou jeanne", "parody:kamisama dolls", + "parody:kamisama hajimemashita", "parody:kamisama minarai himitsu no cocotama", "parody:kamisama ni natta hi", "parody:kampfer", @@ -1103,6 +1134,7 @@ object Parody : TagList { "parody:katekyo hitman reborn", "parody:katsute mahou shoujo to aku wa tekitai shite ita.", "parody:katte ni kaizou", + "parody:kawaii dake ja nai shikimori-san", "parody:kawaikereba hentai demo suki ni natte kuremasu ka", "parody:kaze no na wa amnesia", "parody:kaze no yojimbo", @@ -1113,6 +1145,7 @@ object Parody : TagList { "parody:kemeko deluxe", "parody:kemono friends", "parody:kemono jihen", + "parody:kenja no deshi o nanoru kenja", "parody:kenja no mago", "parody:kenka banchou otome", "parody:kenkou zenrakei suieibu umishou", @@ -1146,6 +1179,7 @@ object Parody : TagList { "parody:kingdom hearts", "parody:kinnikuman", "parody:kino no tabi", + "parody:kinsou no vermeil", "parody:kira kira", "parody:kirakira precure a la mode", "parody:kirarin revolution", @@ -1173,6 +1207,7 @@ object Parody : TagList { "parody:komi-san wa komyushou desu.", "parody:konjiki no word master", "parody:kono aozora ni yakusoku o", + "parody:kono healer mendokusai", "parody:kono oto tomare", "parody:kono subarashii sekai ni syukufuku o", "parody:konto koroshiya 1989", @@ -1216,9 +1251,11 @@ object Parody : TagList { "parody:kyoukai no rinne", "parody:kyoukai senjou no horizon", "parody:kyouryuu wakusei", + "parody:kyuuketsuki sugu shinu", "parody:kyuukyoku choujin r", "parody:kyuukyoku hentai kamen", "parody:kyuukyoku shinka shita full dive rpg ga genjitsu yori mo kusogee dattara", + "parody:kyuukyuu sentai gogofive", "parody:kyuushu sentai danjija", "parody:la corda doro", "parody:la pucelle", @@ -1232,6 +1269,7 @@ object Parody : TagList { "parody:le ranch", "parody:league of legends", "parody:left 4 dead", + "parody:legend of legaia", "parody:legend of lyon flare", "parody:legend of queen opala", "parody:legend of the cryptids", @@ -1326,6 +1364,8 @@ object Parody : TagList { "parody:mahouka koukou no rettousei", "parody:mahoutsukai no yakusoku", "parody:mahoutsukai no yome", + "parody:mahoutsukai reimeiki", + "parody:mai mai miracle", "parody:mai-hime", "parody:mai-otome", "parody:mairimashita iruma-kun", @@ -1383,6 +1423,7 @@ object Parody : TagList { "parody:mayoi neko overrun", "parody:maze runner", "parody:mazinger z", + "parody:me me me", "parody:mecha mote", "parody:mechakko dotakon", "parody:medabots", @@ -1423,6 +1464,7 @@ object Parody : TagList { "parody:mirmo de pon", "parody:miss machiko", "parody:mission impossible", + "parody:misumisou", "parody:mitsudomoe", "parody:mitsume ga tooru", "parody:mitsumete knight", @@ -1479,7 +1521,6 @@ object Parody : TagList { "parody:muv-luv alternative total eclipse", "parody:mx0", "parody:my dad the rock star", - "parody:my dress-up darling", "parody:my hero academia", "parody:my life as a teenage robot", "parody:my little pony friendship is magic", @@ -1508,6 +1549,7 @@ object Parody : TagList { "parody:nazo no kanojo x", "parody:nee chanto shiyou yo", "parody:nee summer", + "parody:needy streamer overload", "parody:nejimaki seirei senki tenkyou no alderamin", "parody:nekketsu saikyou go-saurer", "parody:nekome kozou", @@ -1563,6 +1605,7 @@ object Parody : TagList { "parody:oda nobuna no yabou", "parody:odin sphere", "parody:odoru daisousasen", + "parody:odyssey", "parody:oira uchuu no tankoufu", "parody:ojama yurei-kun", "parody:ojamajo doremi", @@ -1636,6 +1679,7 @@ object Parody : TagList { "parody:parappa the rapper", "parody:parasite eve", "parody:parasyte", + "parody:paripi koumei", "parody:pastel", "parody:pastel yumi", "parody:patlabor", @@ -1709,6 +1753,7 @@ object Parody : TagList { "parody:pu-li-ru-la", "parody:puella magi madoka magica", "parody:pumpkin scissors", + "parody:punch-out", "parody:puppet princess of marl kingdom", "parody:pussy saga", "parody:puyo puyo", @@ -1740,6 +1785,7 @@ object Parody : TagList { "parody:red pride of eden", "parody:redline", "parody:redwall", + "parody:refrain no chika meikyuu to majo no ryodan", "parody:regalia the three sacred stars", "parody:reibaishi izuna", "parody:remi nobodys girl", @@ -1822,6 +1868,7 @@ object Parody : TagList { "parody:sarah and duck", "parody:sasameki koto", "parody:sasami magical girls club", + "parody:satsukare", "parody:savage reign", "parody:sayonara zetsubou sensei", "parody:school days", @@ -1838,6 +1885,7 @@ object Parody : TagList { "parody:seiken densetsu", "parody:seiken densetsu 2", "parody:seiken densetsu 3", + "parody:seiken densetsu ds", "parody:seikesshou albatross", "parody:seikon no qwaser", "parody:seirei no moribito", @@ -1869,12 +1917,14 @@ object Parody : TagList { "parody:sensei no bulge", "parody:sentimental graffiti", "parody:sentouin hakenshimasu", + "parody:senyoku no sigrdrifa", "parody:serial experiments lain", "parody:seto no hanayome", "parody:seven mortal sins", "parody:seven of seven", "parody:sewayaki kitsune no senko-san", "parody:sexfriend", + "parody:shachiku-san wa youjo yuurei ni iyasaretai.", "parody:shadow of the colossus", "parody:shakugan no shana", "parody:shakunetsu no nirai kanai", @@ -1912,6 +1962,7 @@ object Parody : TagList { "parody:shinryaku ika musume", "parody:shinseiki inma seiden", "parody:shinsekai yori", + "parody:shiroi suna no aquatope", "parody:shironeko project", "parody:shisha no teikoku", "parody:shishunki renaissance david-kun", @@ -1951,9 +2002,13 @@ object Parody : TagList { "parody:snow white and the seven dwarfs", "parody:sokihei m.d. geist", "parody:solatorobo", + ) + + override fun getTags2(): List = listOf( "parody:soltyrei", "parody:sonic soldier borgman", "parody:sonic the hedgehog", + "parody:sono bisque doll wa koi o suru", "parody:sono hanabira ni kuchizuke o", "parody:sora no iro mizu no iro", "parody:sora no kanata no dystopia", @@ -1967,6 +2022,7 @@ object Parody : TagList { "parody:soredemo machi wa mawatteiru", "parody:soredemo tsuma o aishiteru", "parody:soromon no kagi", + "parody:sou-bou-tei kowasubeshi", "parody:soukou kijo iris", "parody:soukyuu no fafner", "parody:soul cradle", @@ -2002,9 +2058,6 @@ object Parody : TagList { "parody:star gladiator", "parody:star ocean", "parody:star ocean 2", - ) - - override fun getTags2() = listOf( "parody:star ocean 3", "parody:star ocean 4", "parody:star trek", @@ -2055,6 +2108,7 @@ object Parody : TagList { "parody:sword art online", "parody:sword art online alternative gun gale online", "parody:sword girls", + "parody:sword of the stranger", "parody:sword world rpg", "parody:sym-bionic titan", "parody:t.u.f.f. puppy", @@ -2087,6 +2141,7 @@ object Parody : TagList { "parody:tantei opera milky holmes", "parody:tantei wa mou shindeiru.", "parody:tari tari", + "parody:tartaros", "parody:tasogare otome x amnesia", "parody:tasogare sakaba uwabami breakers", "parody:tatakae tarantella", @@ -2236,6 +2291,7 @@ object Parody : TagList { "parody:the x-files", "parody:they are my noble masters", "parody:this ugly yet beautiful world", + "parody:thomas the tank engine and friends", "parody:threads of fate", "parody:three from prostokvashino", "parody:thundercats", @@ -2244,8 +2300,7 @@ object Parody : TagList { "parody:tiny toons", "parody:to heart", "parody:to love-ru", - "parody:toaru kagaku no railgun", - "parody:toaru majutsu no index", + "parody:toaru project", "parody:tobe isami", "parody:togainu no chi", "parody:toheart2", @@ -2259,6 +2314,7 @@ object Parody : TagList { "parody:tokyo mew mew", "parody:tokyo red hood", "parody:tom and jerry", + "parody:tom clancys ghost recon", "parody:tom clancys rainbow six", "parody:tomb raider", "parody:tomodachi no imouto ga ore ni dake uzai", @@ -2306,6 +2362,7 @@ object Parody : TagList { "parody:twinkle review", "parody:uchi no musume ni te o dasuna", "parody:uchouten kazoku", + "parody:uchuu eiyuu monogatari", "parody:uchuu kaizoku sara", "parody:uchuu kazoku carlvinson", "parody:uchuu no kishi tekkaman", @@ -2332,6 +2389,7 @@ object Parody : TagList { "parody:uta no prince-sama", "parody:utawarerumono", "parody:utawarerumono itsuwari no kamen", + "parody:utsukushiki sei no dendoushi rei rei", "parody:uzaki-chan wa asobitai", "parody:va-11 hall-a", "parody:valkyria chronicles", @@ -2412,6 +2470,7 @@ object Parody : TagList { "parody:witchblade", "parody:witchs weapon", "parody:with you", + "parody:wixoss diva a live", "parody:wizard of oz", "parody:wolfs rain", "parody:wooser no sonohigurashi", @@ -2437,6 +2496,7 @@ object Parody : TagList { "parody:yagate kimi ni naru", "parody:yahari ore no seishun love come wa machigatteiru", "parody:yakitate japan", + "parody:yakumo-san wa ezuke ga shitai.", "parody:yakushiji ryouko no kaiki jikenbo", "parody:yakusoku no neverland", "parody:yama no susume", @@ -2453,6 +2513,7 @@ object Parody : TagList { "parody:yiik", "parody:yin yang yo", "parody:yoake mae yori ruriiro na", + "parody:yofukashi no uta", "parody:yokohama kaidashi kikou", "parody:yomawari", "parody:yondemasuyo azazel-san", diff --git a/app/src/main/java/exh/eh/tags/ReClass.kt b/app/src/main/java/exh/eh/tags/Reclass.kt similarity index 78% rename from app/src/main/java/exh/eh/tags/ReClass.kt rename to app/src/main/java/exh/eh/tags/Reclass.kt index 9b26dc90d..f3517c8b0 100644 --- a/app/src/main/java/exh/eh/tags/ReClass.kt +++ b/app/src/main/java/exh/eh/tags/Reclass.kt @@ -1,8 +1,7 @@ package exh.eh.tags -object ReClass : TagList { - - override fun getTags1() = listOf( +object Reclass : TagList { + override fun getTags1(): List = listOf( "reclass:artistcg", "reclass:asianporn", "reclass:cosplay", diff --git a/app/src/main/java/exh/eh/tags/TagList.kt b/app/src/main/java/exh/eh/tags/TagList.kt index 02496643a..7584e4915 100644 --- a/app/src/main/java/exh/eh/tags/TagList.kt +++ b/app/src/main/java/exh/eh/tags/TagList.kt @@ -7,12 +7,9 @@ interface TagList { fun getTags3(): List = emptyList() - fun getTags4(): List = emptyList() - - fun getTags() = listOf( + fun getTags(): List> = listOf( getTags1(), getTags2(), getTags3(), - getTags4(), ) } From 0ed26dbc49b380999e1aba4fe6c0fc6a3baab898 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Sat, 13 Aug 2022 15:48:49 -0400 Subject: [PATCH 31/34] More fixes --- .../kanade/tachiyomi/ui/base/controller/DialogController.kt | 2 +- .../eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt | 1 + .../main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt | 1 + .../kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt | 4 ++-- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt index ac8549c36..c472acc71 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt @@ -98,7 +98,7 @@ abstract class DialogController : Controller { /** * Dismiss the dialog and pop this controller */ - private fun dismissDialog() { + protected fun dismissDialog() { if (dismissed) { return } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt index 4217532aa..4004404da 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt @@ -474,6 +474,7 @@ class LibrarySettingsSheet( item.checked = !item.checked when (item) { startReadingButton -> preferences.startReadingButton().set((item.checked)) + else -> Unit } adapter.notifyItemChanged(item) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index bdf96abd7..66661557a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -29,6 +29,7 @@ import coil.request.ImageRequest import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeType +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.snackbar.Snackbar import dev.chrisbanes.insetter.applyInsetter diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt index bdd6712bf..77ed8348e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderTransitionView.kt @@ -54,7 +54,7 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At binding.upperText.textAlignment = TEXT_ALIGNMENT_TEXT_START val isPrevDownloaded = downloadManager.isChapterDownloaded( prevChapter, - manga + manga, ) val isCurrentDownloaded = transition.from.pageLoader is DownloadPageLoader binding.upperText.text = buildSpannedString { @@ -89,7 +89,7 @@ class ReaderTransitionView @JvmOverloads constructor(context: Context, attrs: At val isCurrentDownloaded = transition.from.pageLoader is DownloadPageLoader val isNextDownloaded = downloadManager.isChapterDownloaded( nextChapter, - manga + manga, ) binding.upperText.text = buildSpannedString { bold { append(context.getString(R.string.transition_finished)) } From e7423e3715b66d97928c854709151425fa3d3c75 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Sat, 6 Aug 2022 19:23:35 -0400 Subject: [PATCH 32/34] Add missing mangadex languages, remove language prettyPrint since its not used (cherry picked from commit 240d821a58de7ac7e186c18db7542ea5efc31d8a) --- app/src/main/java/exh/md/utils/MdLang.kt | 89 ++++++++++++------------ 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/exh/md/utils/MdLang.kt b/app/src/main/java/exh/md/utils/MdLang.kt index 9edaa1f3f..e49b0b776 100644 --- a/app/src/main/java/exh/md/utils/MdLang.kt +++ b/app/src/main/java/exh/md/utils/MdLang.kt @@ -1,49 +1,52 @@ package exh.md.utils @Suppress("unused") -enum class MdLang(val lang: String, val prettyPrint: String, val extLang: String = lang) { - ENGLISH("en", "English"), - JAPANESE("ja", "Japanese"), - POLISH("pl", "Polish"), - SERBO_CROATIAN("rs", "Serbo-Croatian", "sh"), - DUTCH("nl", "Dutch"), - ITALIAN("it", "IT"), - RUSSIAN("ru", "Russian"), - GERMAN("de", "German"), - HUNGARIAN("hu", "Hungarian"), - FRENCH("fr", "French"), - FINNISH("fi", "Finnish"), - VIETNAMESE("vi", "Vietnamese"), - GREEK("el", "Greek"), - BULGARIAN("bg", "BULGARIN"), - SPANISH_ES("es", "Spanish (Es)"), - PORTUGUESE_BR("pt-br", "Portuguese (Br)", "pt-BR"), - PORTUGUESE("pt", "Portuguese (Pt)"), - SWEDISH("sv", "Swedish"), - ARABIC("ar", "Arabic"), - DANISH("da", "Danish"), - CHINESE_SIMPLIFIED("zh", "Chinese (Simp)", "zh-Hans"), - BENGALI("bn", "Bengali"), - ROMANIAN("ro", "Romanian"), - CZECH("cs", "Czech"), - MONGOLIAN("mn", "Mongolian"), - TURKISH("tr", "Turkish"), - INDONESIAN("id", "Indonesian"), - KOREAN("kr", "Korean", "ko"), - SPANISH_LATAM("es-la", "Spanish (LATAM)", "es-419"), - PERSIAN("fa", "Persian"), - MALAY("ms", "Malay"), - THAI("th", "Thai"), - CATALAN("ca", "Catalan"), - FILIPINO("tl", "Filipino", "fil"), - CHINESE_TRAD("zh-hk", "Chinese (Trad)", "zh-Hant"), - UKRAINIAN("uk", "Ukrainian"), - BURMESE("my", "Burmese"), - LINTHUANIAN("lt", "Lithuanian"), - HEBREW("he", "Hebrew"), - HINDI("hi", "Hindi"), - NORWEGIAN("no", "Norwegian"), - NEPALI("ne", "Nepali") +enum class MdLang(val lang: String, val extLang: String = lang) { + ENGLISH("en"), + JAPANESE("ja"), + POLISH("pl"), + SERBO_CROATIAN("rs", "sh"), + DUTCH("nl"), + ITALIAN("it"), + RUSSIAN("ru"), + GERMAN("de"), + HUNGARIAN("hu"), + FRENCH("fr"), + FINNISH("fi"), + VIETNAMESE("vi"), + GREEK("el"), + BULGARIAN("bg"), + SPANISH_ES("es"), + PORTUGUESE_BR("pt-br", "pt-BR"), + PORTUGUESE("pt"), + SWEDISH("sv"), + ARABIC("ar"), + DANISH("da"), + CHINESE_SIMPLIFIED("zh", "zh-Hans"), + BENGALI("bn"), + ROMANIAN("ro"), + CZECH("cs"), + MONGOLIAN("mn"), + TURKISH("tr"), + INDONESIAN("id"), + KOREAN("kr", "ko"), + SPANISH_LATAM("es-la", "es-419"), + PERSIAN("fa"), + MALAY("ms"), + THAI("th"), + CATALAN("ca"), + FILIPINO("tl", "fil"), + CHINESE_TRAD("zh-hk", "zh-Hant"), + UKRAINIAN("uk"), + BURMESE("my"), + LINTHUANIAN("lt"), + HEBREW("he"), + HINDI("hi"), + NORWEGIAN("no"), + NEPALI("ne"), + LATIN("la"), + TAMIL("ta"), + KAZAKH("kk"), ; companion object { From 9a291e6da45d1a1d259293e4adaef97bb2edc926 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 14 Aug 2022 11:49:19 -0400 Subject: [PATCH 33/34] Fix sources not loading (cherry picked from commit 1f79444a531d0f4ec93cc953f3d82ea3c1094471) # Conflicts: # app/proguard-rules.pro --- build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 8d647913d..307af97ca 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,9 @@ buildscript { dependencies { + // Pinning to older version of R8 due to weird forced optimizations in newer versions in + // version bundled with AGP + // https://mvnrepository.com/artifact/com.android.tools/r8?repo=google + classpath("com.android.tools:r8:3.1.66") classpath(libs.android.shortcut.gradle) classpath(libs.google.services.gradle) classpath(libs.aboutlibraries.gradle) From b7779ba14f9e24d619ecacc2f62abc88bcf1b89b Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 11 Jun 2022 11:38:16 -0400 Subject: [PATCH 34/34] v1.8.5 --- .github/ISSUE_TEMPLATE.md | 2 +- .github/ISSUE_TEMPLATE/report_issue.yml | 4 ++-- .github/ISSUE_TEMPLATE/request_feature.yml | 2 +- .github/workflows/TachiyomiSY-Release-Builder.yml | 5 ----- .github/workflows/build_check.yml | 5 ----- app/build.gradle.kts | 4 ++-- app/src/main/res/raw/changelog_release.xml | 5 +++++ 7 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 26f8b57e3..057c48a91 100755 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -3,7 +3,7 @@ I acknowledge that: - I have updated: - - To the latest version of the app (stable is v1.8.4) + - To the latest version of the app (stable is v1.8.5) - All extensions - I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/ - If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions diff --git a/.github/ISSUE_TEMPLATE/report_issue.yml b/.github/ISSUE_TEMPLATE/report_issue.yml index c06dd5a25..c4a5a6002 100644 --- a/.github/ISSUE_TEMPLATE/report_issue.yml +++ b/.github/ISSUE_TEMPLATE/report_issue.yml @@ -53,7 +53,7 @@ body: label: Tachiyomi version description: You can find your Tachiyomi version in **More → About**. placeholder: | - Example: "1.8.4" + Example: "1.8.5" validations: required: true @@ -98,7 +98,7 @@ body: required: true - label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/). required: true - - label: I have updated the app to version **[1.8.4](https://github.com/jobobby04/tachiyomisy/releases/latest)**. + - label: I have updated the app to version **[1.8.5](https://github.com/jobobby04/tachiyomisy/releases/latest)**. required: true - label: I have updated all installed extensions. required: true diff --git a/.github/ISSUE_TEMPLATE/request_feature.yml b/.github/ISSUE_TEMPLATE/request_feature.yml index c5edf0b9c..b1ae87ed8 100644 --- a/.github/ISSUE_TEMPLATE/request_feature.yml +++ b/.github/ISSUE_TEMPLATE/request_feature.yml @@ -33,7 +33,7 @@ body: required: true - label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose). required: true - - label: I have updated the app to version **[1.8.4](https://github.com/jobobby04/tachiyomisy/releases/latest)**. + - label: I have updated the app to version **[1.8.5](https://github.com/jobobby04/tachiyomisy/releases/latest)**. required: true - label: I will fill out all of the requested information in this form. required: true diff --git a/.github/workflows/TachiyomiSY-Release-Builder.yml b/.github/workflows/TachiyomiSY-Release-Builder.yml index cd02bf6e2..eb7a29d17 100644 --- a/.github/workflows/TachiyomiSY-Release-Builder.yml +++ b/.github/workflows/TachiyomiSY-Release-Builder.yml @@ -37,11 +37,6 @@ jobs: java-version: 11 distribution: adopt - - name: Copy CI gradle.properties - run: | - mkdir -p ~/.gradle - cp .github/runner-files/ci-gradle.properties ~/.gradle/gradle.properties - - name: Write google-services.json uses: DamianReeves/write-file-action@v1.0 with: diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index 90e9eebb7..3968a1aa9 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -33,11 +33,6 @@ jobs: java-version: 11 distribution: adopt - - name: Copy CI gradle.properties - run: | - mkdir -p ~/.gradle - cp .github/runner-files/ci-gradle.properties ~/.gradle/gradle.properties - - name: Build app uses: gradle/gradle-command-action@v2 with: diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c00dc01c6..16499ef62 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -27,8 +27,8 @@ android { applicationId = "eu.kanade.tachiyomi.sy" minSdk = AndroidConfig.minSdk targetSdk = AndroidConfig.targetSdk - versionCode = 35 - versionName = "1.8.4" + versionCode = 36 + versionName = "1.8.5" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"") diff --git a/app/src/main/res/raw/changelog_release.xml b/app/src/main/res/raw/changelog_release.xml index dc8585fcf..ab037a5be 100755 --- a/app/src/main/res/raw/changelog_release.xml +++ b/app/src/main/res/raw/changelog_release.xml @@ -1,5 +1,10 @@ + + [b]Based on Tachiyomi stable 0.13.6(from 0.13.5)[/b] + Update EH tags for auto-complete filter + Update supported MangaDex languages + [b]Based on Tachiyomi stable 0.13.5(from 0.13.4)[/b] Fix On Hiatus dynamic category