diff --git a/Twilight.cmd b/Twilight.cmd index 105fddd..9b7ad19 100644 --- a/Twilight.cmd +++ b/Twilight.cmd @@ -15,9 +15,6 @@ PAUSE ) ) -IF %TEST% == 1 ( - wsl java -jar Twilight.jar --test -) CHOICE /M PATCH IF %ERRORLEVEL% == 1 ( diff --git a/build.gradle.kts b/build.gradle.kts index ff092fb..e312376 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,13 +19,11 @@ implementation("com.fasterxml.jackson.core:jackson-databind:2.16.0") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.16.0") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.16.0") - implementation("com.github.pemistahl:lingua:1.2.2") implementation("com.google.protobuf:protobuf-java:3.25.1") implementation("com.google.protobuf:protobuf-kotlin:3.25.1") implementation("com.ibm.icu:icu4j:74.1") implementation("com.lmax:disruptor:3.4.4") implementation("com.sun.mail:jakarta.mail:2.0.1") - implementation("commons-cli:commons-cli:1.6.0") implementation("commons-codec:commons-codec:1.16.0") implementation("commons-io:commons-io:2.15.1") implementation("io.netty:netty-all:4.1.101.Final") @@ -57,10 +55,6 @@ useJUnitPlatform() } -tasks.shadowJar { - isZip64 = true -} - tasks.withType { kotlinOptions.jvmTarget = "21" } diff --git a/src/main/kotlin/net/taehui/twilight/JSON.kt b/src/main/kotlin/net/taehui/twilight/JSON.kt index 498a63a..e06a6a1 100644 --- a/src/main/kotlin/net/taehui/twilight/JSON.kt +++ b/src/main/kotlin/net/taehui/twilight/JSON.kt @@ -107,6 +107,10 @@ } } + class N2MTLanguage( + val langCode: String = "" + ) + class QwilightEstablish { var qwilightName = "" var hash = "" diff --git a/src/main/kotlin/net/taehui/twilight/Twilight.kt b/src/main/kotlin/net/taehui/twilight/Twilight.kt index 69c2ebc..e4285af 100644 --- a/src/main/kotlin/net/taehui/twilight/Twilight.kt +++ b/src/main/kotlin/net/taehui/twilight/Twilight.kt @@ -10,9 +10,6 @@ import net.taehui.twilight.system.* import net.taehui.twilight.taehui.TaehuiBoot import net.taehui.twilight.www.WwwBoot -import org.apache.commons.cli.DefaultParser -import org.apache.commons.cli.Option -import org.apache.commons.cli.Options import org.apache.commons.lang3.SystemUtils import org.fusesource.jansi.AnsiConsole import java.io.IOException @@ -42,10 +39,6 @@ Runtime.getRuntime().exit(1) } - val o = Options() - o.addOption(Option("t", "test", false, "Test")) - val isTest = DefaultParser().parse(o, args).hasOption("test") - val eventLoopGroup = if (SystemUtils.IS_OS_LINUX) EpollEventLoopGroup() else NioEventLoopGroup() val eventChannel: Class = if (SystemUtils.IS_OS_LINUX) EpollServerSocketChannel::class.java else NioServerSocketChannel::class.java @@ -83,11 +76,7 @@ QwilightNamesSystem.loadQwilightNames() AwilightHandler.eventLoopGroup = eventLoopGroup AwilightHandler.setAwilightCount(Configure.awilightCount) - if (isTest) { - AvatarHandler.sendClose("") - } else { - AvatarHandler.sendClose(IO.handleSystem()) - } + AvatarHandler.sendClose(IO.handleSystem()) } finally { WitSystem.dispose() PlatformIDSystem.savePlatformID() diff --git a/src/main/kotlin/net/taehui/twilight/system/AbilityClassSystem.kt b/src/main/kotlin/net/taehui/twilight/system/AbilityClassSystem.kt index 3488a5b..2a938dd 100644 --- a/src/main/kotlin/net/taehui/twilight/system/AbilityClassSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/AbilityClassSystem.kt @@ -7,7 +7,7 @@ object AbilityClassSystem : Logger { enum class AbilityClassVariety(@JvmField val value: Int) { - ETC(-1), _5K(0), _7K(1), _9K(2); + ETC(-1), INPUT_MODE_5K(0), INPUT_MODE_7K(1), INPUT_MODE_9K(2); @JsonValue fun getValue(): Int { @@ -48,9 +48,9 @@ Path.of( when (abilityClassVariety) { AbilityClassVariety.ETC -> "" - AbilityClassVariety._5K -> "abilityClass5K" - AbilityClassVariety._7K -> "abilityClass7K" - AbilityClassVariety._9K -> "abilityClass9K" + AbilityClassVariety.INPUT_MODE_5K -> "abilityClass5K" + AbilityClassVariety.INPUT_MODE_7K -> "abilityClass7K" + AbilityClassVariety.INPUT_MODE_9K -> "abilityClass9K" }, path ).pathString @@ -99,9 +99,9 @@ ) } - loadAbilityClass(AbilityClassVariety._5K) - loadAbilityClass(AbilityClassVariety._7K) - loadAbilityClass(AbilityClassVariety._9K) + loadAbilityClass(AbilityClassVariety.INPUT_MODE_5K) + loadAbilityClass(AbilityClassVariety.INPUT_MODE_7K) + loadAbilityClass(AbilityClassVariety.INPUT_MODE_9K) logInfo("Loaded Ability Class") } diff --git a/src/main/kotlin/net/taehui/twilight/system/AbilitySystem.kt b/src/main/kotlin/net/taehui/twilight/system/AbilitySystem.kt index 02cede2..47c601f 100644 --- a/src/main/kotlin/net/taehui/twilight/system/AbilitySystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/AbilitySystem.kt @@ -42,9 +42,9 @@ private val noteIDAbilityMap = mapOf>( Pair(AbilityClassSystem.AbilityClassVariety.ETC, AbilityMap()), - Pair(AbilityClassSystem.AbilityClassVariety._5K, AbilityMap()), - Pair(AbilityClassSystem.AbilityClassVariety._7K, AbilityMap()), - Pair(AbilityClassSystem.AbilityClassVariety._9K, AbilityMap()) + Pair(AbilityClassSystem.AbilityClassVariety.INPUT_MODE_5K, AbilityMap()), + Pair(AbilityClassSystem.AbilityClassVariety.INPUT_MODE_7K, AbilityMap()), + Pair(AbilityClassSystem.AbilityClassVariety.INPUT_MODE_9K, AbilityMap()) ) private val noteIDAbilityIDsMap = AbilityMap>() private val noteIDAbilityNamesMap = AbilityMap>() @@ -117,9 +117,9 @@ try { val abilityMap = defaultAbility.abilityMap noteIDAbilityMap[AbilityClassSystem.AbilityClassVariety.ETC]?.wipe() - noteIDAbilityMap[AbilityClassSystem.AbilityClassVariety._5K]?.wipe() - noteIDAbilityMap[AbilityClassSystem.AbilityClassVariety._7K]?.wipe() - noteIDAbilityMap[AbilityClassSystem.AbilityClassVariety._9K]?.wipe() + noteIDAbilityMap[AbilityClassSystem.AbilityClassVariety.INPUT_MODE_5K]?.wipe() + noteIDAbilityMap[AbilityClassSystem.AbilityClassVariety.INPUT_MODE_7K]?.wipe() + noteIDAbilityMap[AbilityClassSystem.AbilityClassVariety.INPUT_MODE_9K]?.wipe() noteIDAbilityIDsMap.wipe() noteIDAbilityNamesMap.wipe() abilityNameAbilityIDsMap.clear() diff --git a/src/main/kotlin/net/taehui/twilight/system/DB.kt b/src/main/kotlin/net/taehui/twilight/system/DB.kt index 2999738..e7b62b5 100644 --- a/src/main/kotlin/net/taehui/twilight/system/DB.kt +++ b/src/main/kotlin/net/taehui/twilight/system/DB.kt @@ -33,22 +33,22 @@ dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_note ( - Note_ID VARCHAR(139), - Note_ID_128 CHAR(32), - Note_ID_256 CHAR(64), - Note_Variety INTEGER, - Artist TEXT, - Title TEXT, - Genre TEXT, - Level_Text TEXT, - Level INTEGER, - Input_Mode INTEGER, - Total_Notes INTEGER, - Is_Salt BOOLEAN, - Ability_5K REAL, - Ability_7K REAL, - Ability_9K REAL, - Length REAL, + Note_ID VARCHAR(139) NOT NULL, + Note_ID_128 CHAR(32) NOT NULL, + Note_ID_256 CHAR(64) NOT NULL, + Note_Variety INTEGER NOT NULL, + Artist TEXT NOT NULL, + Title TEXT NOT NULL, + Genre TEXT NOT NULL, + Level_Text TEXT NOT NULL, + Level INTEGER NOT NULL, + Input_Mode INTEGER NOT NULL, + Total_Notes INTEGER NOT NULL, + Is_Salt BOOLEAN NOT NULL, + Ability_5K REAL NOT NULL, + Ability_7K REAL NOT NULL, + Ability_9K REAL NOT NULL, + Length REAL NOT NULL, PRIMARY KEY (Note_ID), KEY (Note_Variety), FULLTEXT (Artist), @@ -58,15 +58,15 @@ KEY (Ability_5K), KEY (Ability_7K), KEY (Ability_9K) - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_comment ( - Date DATETIME, - Note_ID VARCHAR(139), - Avatar VARCHAR(20), + Date DATETIME NOT NULL, + Note_ID VARCHAR(139) NOT NULL, + Avatar VARCHAR(20) NOT NULL, Multiplier REAL, Auto_Mode INTEGER, Note_Salt_Mode INTEGER, @@ -84,7 +84,7 @@ Is_P BOOLEAN, Point REAL, Salt INTEGER, - Comment_ID CHAR(128), + Comment_ID CHAR(128) NOT NULL, Is_Max BOOLEAN, Is_Paused BOOLEAN, Input_Flags INTEGER, @@ -114,41 +114,41 @@ CHECK (Band >= 0), CHECK (Point >= 0.0 AND Point <= 1.0), CHECK (Input_Flags >= 0 AND Input_Flags <= 15) - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_bundle ( - Avatar VARCHAR(20), - Date DATETIME, - Name VARCHAR(191), - Length LONG, - Competence INTEGER, - Variety INTEGER, - Etc TEXT, + Avatar VARCHAR(20) NOT NULL, + Date DATETIME NOT NULL, + Name VARCHAR(191) NOT NULL, + Length LONG NOT NULL, + Competence INTEGER NOT NULL, + Variety INTEGER NOT NULL, + Etc TEXT NOT NULL, PRIMARY KEY (Avatar, Name), FOREIGN KEY (Avatar) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE, CHECK (Competence IN (0, 1, 2)), CHECK (Variety IN (0, 1, 2)) - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_ubuntu ( - Avatar VARCHAR(20), - Ubuntu VARCHAR(20), + Avatar VARCHAR(20) NOT NULL, + Ubuntu VARCHAR(20) NOT NULL, PRIMARY KEY (Avatar, Ubuntu), FOREIGN KEY (Avatar) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY (Ubuntu) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_avatar ( - Avatar VARCHAR(20), + Avatar VARCHAR(20) NOT NULL, Silent_Site INTEGER, Notify_Ubuntu INTEGER, Default_Bundle_Competence INTEGER, @@ -162,86 +162,95 @@ CHECK (Default_Bundle_Competence IN (0, 1, 2, 3)), CHECK (IO_Competence IN (0, 1, 2, 3)), CHECK (Notify_Save_Bundle IN (0, 1, 2, 3)) - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_title ( - Avatar VARCHAR(20), - Title_ID CHAR(36), + Avatar VARCHAR(20) NOT NULL, + Title_ID CHAR(36) NOT NULL, PRIMARY KEY (Avatar), FOREIGN KEY (Avatar) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_edge ( - Avatar VARCHAR(20), - Edge_ID CHAR(36), + Avatar VARCHAR(20) NOT NULL, + Edge_ID CHAR(36) NOT NULL, PRIMARY KEY (Avatar), FOREIGN KEY (Avatar) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE, KEY (Edge_ID) - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_site ( - Site_ID CHAR(36), - Avatar_ID VARCHAR(20), - Avatar_Name VARCHAR(255), - Date LONG, - Site_Yell TEXT, - Platform_ID LONG, + Site_ID CHAR(36) NOT NULL, + Avatar_ID VARCHAR(20) NOT NULL, + Avatar_Name VARCHAR(255) NOT NULL, + Date LONG NOT NULL, + Site_Yell TEXT NOT NULL, + Platform_ID LONG NOT NULL, KEY (Site_ID), KEY (Platform_ID) - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_level ( - Avatar VARCHAR(20), - Level_ID CHAR(36), - Date DATETIME, + Avatar VARCHAR(20) NOT NULL, + Level_ID CHAR(36) NOT NULL, + Date DATETIME NOT NULL, PRIMARY KEY (Avatar, Level_ID), FOREIGN KEY (Avatar) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_commentary ( - Note_ID VARCHAR(139), - Avatar VARCHAR(20), - Commentary TEXT, + Note_ID VARCHAR(139) NOT NULL, + Avatar VARCHAR(20) NOT NULL, + Commentary TEXT NOT NULL, PRIMARY KEY (Avatar, Note_ID), FOREIGN KEY (Avatar) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_translated ( - Text VARCHAR(766), - Target_Language CHAR(2), - Translated_Text TEXT, + Text VARCHAR(766) NOT NULL, + Target_Language VARCHAR(5) NOT NULL, + Translated_Text TEXT NOT NULL, PRIMARY KEY (Text, Target_Language) - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB + """.trimIndent() + ) + dbStatement.executeUpdate( + """ + CREATE TABLE IF NOT EXISTS tw_language ( + Text VARCHAR(766) NOT NULL, + Language VARCHAR(5) NOT NULL, + PRIMARY KEY (Text) + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) dbStatement.executeUpdate( """ CREATE TABLE IF NOT EXISTS tw_favor ( - Note_ID VARCHAR(139), - Avatar VARCHAR(20), - Date DATETIME, - Favor BOOLEAN, + Note_ID VARCHAR(139) NOT NULL, + Avatar VARCHAR(20) NOT NULL, + Date DATETIME NOT NULL, + Favor BOOLEAN NOT NULL, PRIMARY KEY (Avatar, Note_ID), FOREIGN KEY (Avatar) REFERENCES tn_avatar(Avatar_ID) ON UPDATE CASCADE ON DELETE CASCADE - ) ENGINE=InnoDB + ) COLLATE=utf8mb4_general_ci ENGINE=InnoDB """.trimIndent() ) } @@ -324,26 +333,60 @@ } } - fun loadTranslatedText(text: String, targetLanguage: String): CompletableFuture { + fun loadLanguage(text: String): CompletableFuture { return logValueFuture { pool.connection.use { it.prepareStatement( """ - SELECT Translated_Text - FROM tw_translated - WHERE Text = ? AND Target_Language = ? + SELECT Language + FROM tw_language + WHERE Text = ? """.trimIndent() ).use { dbStatement -> dbStatement.setString(1, text) - dbStatement.setString(2, targetLanguage) dbStatement.executeQuery().use { rows -> - if (rows.next()) rows.getString("Translated_Text") else "" + if (rows.next()) rows.getString("Language") else "" } } } } } + fun saveLanguage(text: String, language: String): CompletableFuture { + return logFuture { + pool.connection.use { + it.prepareStatement( + """ + REPLACE INTO tw_language + VALUES(?, ?) + """.trimIndent() + ).use { dbStatement -> + dbStatement.setString(1, text) + dbStatement.setString(2, language) + dbStatement.execute() + } + } + } + } + + fun loadTranslatedText(text: String, targetLanguage: String): String { + return pool.connection.use { + it.prepareStatement( + """ + SELECT Translated_Text + FROM tw_translated + WHERE Text = ? AND Target_Language = ? + """.trimIndent() + ).use { dbStatement -> + dbStatement.setString(1, text) + dbStatement.setString(2, targetLanguage) + dbStatement.executeQuery().use { rows -> + if (rows.next()) rows.getString("Translated_Text") else "" + } + } + } + } + fun saveTranslatedText(text: String, targetLanguage: String, translatedText: String): CompletableFuture { return logFuture { pool.connection.use { @@ -550,31 +593,32 @@ fun getWipeComments(): CompletableFuture> { return logValueFuture { + val commentIDs = mutableSetOf() + pool.connection.use { + it.prepareStatement( + """ + SELECT Comment_ID + FROM tw_comment + WHERE Is_Max = true + """.trimIndent() + ).use { dbStatement -> + dbStatement.executeQuery().use { rows -> + while (rows.next()) { + commentIDs.add(rows.getString("Comment_ID")) + } + } + } + } Files.newDirectoryStream(TwilightComponent.COMMENT_ENTRY_PATH).use { commentEntryPaths -> commentEntryPaths.map { commentEntryPath -> Files.list(commentEntryPath).use { commentFilePaths -> commentFilePaths.map { commentFilePath -> - pool.connection.use { - it.prepareStatement( - """ - SELECT Comment_ID - FROM tw_comment - WHERE Comment_ID = ? - """.trimIndent() - ).use { dbStatement -> - dbStatement.setString( - 1, FilenameUtils.removeExtension(commentFilePath.fileName.toString()) - ) - dbStatement.executeQuery().use { rows -> - if (rows.next()) { - null - } else { - commentFilePath - } - } - } + if (commentIDs.contains(FilenameUtils.removeExtension(commentFilePath.fileName.toString()))) { + null + } else { + commentFilePath } - }.toList() + } } }.flatMap { it.toList() }.filterNotNull() } @@ -596,32 +640,40 @@ fun getWipeBundles(): CompletableFuture> { return logValueFuture { + data class BundleID(val avatarID: String, val bundleName: String) + + val bundleIDs = mutableSetOf() + pool.connection.use { + it.prepareStatement( + """ + SELECT Avatar, Name + FROM tw_bundle + """.trimIndent() + ).use { dbStatement -> + dbStatement.executeQuery().use { rows -> + while (rows.next()) { + bundleIDs.add(BundleID(rows.getString("Avatar"), rows.getString("Name"))) + } + } + } + } + Files.newDirectoryStream(TwilightComponent.BUNDLE_ENTRY_PATH).use { bundleEntryPaths -> bundleEntryPaths.map { bundleEntryPath -> Files.list(bundleEntryPath).use { bundleFilePaths -> bundleFilePaths.map { bundleFilePath -> - pool.connection.use { - it.prepareStatement( - """ - SELECT Avatar, Name - FROM tw_bundle - WHERE Name = ? AND Avatar = ? - """.trimIndent() - ).use { dbStatement -> - dbStatement.setString( - 1, FilenameUtils.removeExtension(bundleFilePath.fileName.toString()) + if (bundleIDs.contains( + BundleID( + bundleEntryPath.fileName.toString(), + FilenameUtils.removeExtension(bundleFilePath.fileName.toString()) ) - dbStatement.setString(2, bundleEntryPath.fileName.toString()) - dbStatement.executeQuery().use { rows -> - if (!rows.next()) { - bundleFilePath - } else { - null - } - } - } + ) + ) { + null + } else { + bundleFilePath } - }.toList() + } } }.flatMap { it.toList() }.filterNotNull() } @@ -1415,7 +1467,7 @@ dbStatement.setDouble( 13, if (isSalt) 0.0 else AbilitySystem.getAbility( - AbilityClassSystem.AbilityClassVariety._5K, + AbilityClassSystem.AbilityClassVariety.INPUT_MODE_5K, noteID128, noteID256 ) @@ -1423,7 +1475,7 @@ dbStatement.setDouble( 14, if (isSalt) 0.0 else AbilitySystem.getAbility( - AbilityClassSystem.AbilityClassVariety._7K, + AbilityClassSystem.AbilityClassVariety.INPUT_MODE_7K, noteID128, noteID256 ) @@ -1431,7 +1483,7 @@ dbStatement.setDouble( 15, if (isSalt) 0.0 else AbilitySystem.getAbility( - AbilityClassSystem.AbilityClassVariety._9K, + AbilityClassSystem.AbilityClassVariety.INPUT_MODE_9K, noteID128, noteID256 ) @@ -1479,7 +1531,7 @@ dbStatement.setDouble( 1, if (isSalt) 0.0 else AbilitySystem.getAbility( - AbilityClassSystem.AbilityClassVariety._5K, + AbilityClassSystem.AbilityClassVariety.INPUT_MODE_5K, noteID128, noteID256 ) @@ -1487,7 +1539,7 @@ dbStatement.setDouble( 2, if (isSalt) 0.0 else AbilitySystem.getAbility( - AbilityClassSystem.AbilityClassVariety._7K, + AbilityClassSystem.AbilityClassVariety.INPUT_MODE_7K, noteID128, noteID256 ) @@ -1495,7 +1547,7 @@ dbStatement.setDouble( 3, if (isSalt) 0.0 else AbilitySystem.getAbility( - AbilityClassSystem.AbilityClassVariety._9K, + AbilityClassSystem.AbilityClassVariety.INPUT_MODE_9K, noteID128, noteID256 ) @@ -2244,13 +2296,13 @@ } }, logValueFuture { pool.connection.use { db -> - val highestDateValue = System.currentTimeMillis() + val millis = System.currentTimeMillis() for (i in 90 downTo 0) { val yyyyMMDD = yyyyMMDDFormat.format( - Instant.ofEpochMilli(highestDateValue - 86400000L * i) + Instant.ofEpochMilli(millis - 86400000L * i) .atZone(ZoneId.systemDefault()) ) - dateSet.add(highestDateValue - 86400000L * i) + dateSet.add(millis - 86400000L * i) db.prepareStatement( """ SELECT COUNT(Comment_ID) AS Count @@ -3093,7 +3145,7 @@ pool.connection.use { it.prepareStatement( """ - SELECT DATE_FORMAT(Date, "%Y-%m") AS Etc_Date, COUNT(*) AS Value + SELECT DATE_FORMAT(Date, "%Y-%m") AS Etc_Date, COUNT(Avatar) AS Value FROM tw_comment GROUP BY Etc_Date HAVING Etc_Date != "0000-00" @@ -3112,7 +3164,7 @@ pool.connection.use { it.prepareStatement( """ - SELECT DATE_FORMAT(Date, "%Y-%m") AS Etc_Date, COUNT(*) AS Value + SELECT DATE_FORMAT(Date, "%Y-%m") AS Etc_Date, COUNT(Avatar_ID) AS Value FROM tn_avatar GROUP BY Etc_Date HAVING Etc_Date != "0000-00" diff --git a/src/main/kotlin/net/taehui/twilight/system/LevelSystem.kt b/src/main/kotlin/net/taehui/twilight/system/LevelSystem.kt index 7fc2d20..0864f88 100644 --- a/src/main/kotlin/net/taehui/twilight/system/LevelSystem.kt +++ b/src/main/kotlin/net/taehui/twilight/system/LevelSystem.kt @@ -121,18 +121,20 @@ } } - private val levelGroupsMap = ConcurrentHashMap>() - private val levelGroupMap = ConcurrentHashMap() - private val levelNamesMap = ConcurrentHashMap>() + private val avatarIDLevelGroupMap = ConcurrentHashMap>() + private val levelNameLevelGroupMap = ConcurrentHashMap() + private val avatarIDLevelNameMap = ConcurrentHashMap>() + private val levelIDDrawingMap = ConcurrentHashMap() val levelNoteIDs = CopyOnWriteArrayList() var isLoading = false fun loadLevel() { isLoading = true try { - levelGroupsMap.clear() - levelGroupMap.clear() - levelNamesMap.clear() + avatarIDLevelGroupMap.clear() + levelNameLevelGroupMap.clear() + avatarIDLevelNameMap.clear() + levelIDDrawingMap.clear() levelNoteIDs.clear() Files.list(TwilightComponent.LEVEL_ENTRY_PATH).use { it.forEach { levelFilePath -> @@ -146,9 +148,17 @@ val avatarID = levelGroup.avatarID val levelName = FilenameUtils.removeExtension(levelFilePath.fileName.toString()) - levelGroupsMap.computeIfAbsent(avatarID) { mutableListOf() }.add(levelGroup) - levelGroupMap[levelName] = levelGroup - levelNamesMap.computeIfAbsent(avatarID) { mutableListOf() }.add(levelName) + avatarIDLevelGroupMap.computeIfAbsent(avatarID) { mutableListOf() }.add(levelGroup) + levelNameLevelGroupMap[levelName] = levelGroup + avatarIDLevelNameMap.computeIfAbsent(avatarID) { mutableListOf() }.add(levelName) + levelGroup.levelItems.forEach { levelItem -> + val levelID = levelItem.levelID + try { + levelIDDrawingMap[levelID] = + Files.readAllBytes(TwilightComponent.LEVEL_ENTRY_PATH.resolve(levelName).resolve("$levelID.png")) + } catch (_: IOException) { + } + } logInfo("Loaded Level (${levelFilePath.fileName})") jm.writerWithDefaultPrettyPrinter().writeValue(levelFilePath.toFile(), levelGroup) @@ -166,7 +176,7 @@ } val avatars: Array - get() = levelGroupsMap.keys.filter { it.isNotEmpty() }.map { + get() = avatarIDLevelGroupMap.keys.filter { it.isNotEmpty() }.map { object { val avatarID = it val avatarName = DB.getAvatarName(it) @@ -174,15 +184,19 @@ }.sortedBy { it.avatarName }.toTypedArray() fun getLevelNames(avatarID: String): Array { - return levelNamesMap[avatarID]?.sorted()?.toTypedArray() ?: emptyArray() + return avatarIDLevelNameMap[avatarID]?.sorted()?.toTypedArray() ?: emptyArray() } fun getLevelGroup(levelName: String): LevelGroup? { - return levelGroupMap[levelName] + return levelNameLevelGroupMap[levelName] + } + + fun getLevelIDDrawing(levelID: String): ByteArray? { + return levelIDDrawingMap[levelID] } fun getSatisfiedLevelItems(qwilightWwwLevel: JSON.QwilightWwwLevel): Stream { - return levelGroupMap.values.stream().flatMap { Arrays.stream(it.levelItems) } + return levelNameLevelGroupMap.values.stream().flatMap { Arrays.stream(it.levelItems) } .filter { it.noteID == qwilightWwwLevel.noteID && it.isSatisfy( qwilightWwwLevel @@ -191,7 +205,7 @@ } fun getLevelItem(levelID: String): LevelGroup.LevelItem? { - return levelGroupMap.values.stream().flatMap { Arrays.stream(it.levelItems) } + return levelNameLevelGroupMap.values.stream().flatMap { Arrays.stream(it.levelItems) } .filter { it.levelID == levelID }.toList().randomOrNull() } } \ No newline at end of file diff --git a/src/main/kotlin/net/taehui/twilight/system/Translator.kt b/src/main/kotlin/net/taehui/twilight/system/Translator.kt index 5d4b44b..834638e 100644 --- a/src/main/kotlin/net/taehui/twilight/system/Translator.kt +++ b/src/main/kotlin/net/taehui/twilight/system/Translator.kt @@ -1,8 +1,6 @@ package net.taehui.twilight.system import com.fasterxml.jackson.databind.ObjectMapper -import com.github.pemistahl.lingua.api.Language -import com.github.pemistahl.lingua.api.LanguageDetectorBuilder import net.taehui.twilight.JSON import net.taehui.twilight.Logger import org.apache.hc.client5.http.HttpResponseException @@ -15,9 +13,6 @@ import java.util.concurrent.CompletableFuture object Translator { - private val languageSystem = - LanguageDetectorBuilder.fromLanguages(Language.KOREAN, Language.ENGLISH, Language.JAPANESE).build() - fun translate( language: String, text: String, @@ -26,54 +21,68 @@ return if (text.length > 766) CompletableFuture.completedFuture( text ) else { - val textLanguage = when (languageSystem.detectLanguageOf(text)) { - Language.KOREAN -> "ko" - Language.ENGLISH -> "en" - Language.JAPANESE -> "ja" - Language.CHINESE -> "zh-CN" - Language.VIETNAMESE -> "vi" - Language.INDONESIAN -> "id" - Language.THAI -> "th" - Language.DUTCH -> "de" - Language.RUSSIAN -> "ru" - Language.SPANISH -> "es" - Language.ITALIAN -> "it" - Language.FRENCH -> "fr" - else -> "" - } - val targetLanguage = language.split('-')[0] - if (textLanguage.isEmpty() || textLanguage == "en" || textLanguage == targetLanguage) CompletableFuture.completedFuture( - text - ) else DB.loadTranslatedText( - text, - targetLanguage - ).thenApply { loadedTranslatedText -> - try { - loadedTranslatedText.ifEmpty { + DB.loadLanguage(text).thenApply { loadedLanguage -> + var textLanguage = loadedLanguage + if (textLanguage.isEmpty()) { + textLanguage = try { HttpClients.createDefault().use { - val dataPost = HttpPost("https://openapi.naver.com/v1/papago/n2mt") + val dataPost = HttpPost("https://openapi.naver.com/v1/papago/detectLangs") dataPost.setHeader("X-Naver-Client-Id", Configure.nhn.nhnID) dataPost.setHeader("X-Naver-Client-Secret", Configure.nhn.nhnPw) dataPost.entity = UrlEncodedFormEntity( listOf( - BasicNameValuePair("source", textLanguage), - BasicNameValuePair("target", targetLanguage), - BasicNameValuePair("text", text) + BasicNameValuePair("query", text) ), StandardCharsets.UTF_8 ) - val translatedText = ObjectMapper().readValue( + ObjectMapper().readValue( it.execute(dataPost, BasicHttpClientResponseHandler()), - JSON.N2MT::class.java - ).message.result.translatedText - DB.saveTranslatedText(text, targetLanguage, translatedText) - translatedText + JSON.N2MTLanguage::class.java + ).langCode.apply { + DB.saveLanguage(text, this) + } + } + } catch (e: HttpResponseException) { + if (e.statusCode != 429) { + logger.logFault(e) + } + "" + } + } + + val targetLanguage = language.split('-')[0] + if (textLanguage.isEmpty() || textLanguage == "en" || textLanguage == targetLanguage) { + text + } else { + val loadedTranslatedText = DB.loadTranslatedText(text, targetLanguage) + var translatedText = loadedTranslatedText + if (translatedText.isEmpty()) { + translatedText = try { + HttpClients.createDefault().use { + val dataPost = HttpPost("https://openapi.naver.com/v1/papago/n2mt") + dataPost.setHeader("X-Naver-Client-Id", Configure.nhn.nhnID) + dataPost.setHeader("X-Naver-Client-Secret", Configure.nhn.nhnPw) + dataPost.entity = UrlEncodedFormEntity( + listOf( + BasicNameValuePair("source", textLanguage), + BasicNameValuePair("target", targetLanguage), + BasicNameValuePair("text", text) + ), StandardCharsets.UTF_8 + ) + ObjectMapper().readValue( + it.execute(dataPost, BasicHttpClientResponseHandler()), + JSON.N2MT::class.java + ).message.result.translatedText.apply { + DB.saveTranslatedText(text, targetLanguage, this) + } + } + } catch (e: HttpResponseException) { + if (e.statusCode != 429) { + logger.logFault(e) + } + text } } - } catch (e: HttpResponseException) { - if (e.statusCode != 429) { - logger.logFault(e) - } - text + translatedText } } } diff --git a/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt b/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt index 3942e2e..63b3369 100644 --- a/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt +++ b/src/main/kotlin/net/taehui/twilight/www/WwwAvatar.kt @@ -456,6 +456,8 @@ val abilityClass5K = params.getOrDefault("abilityClass5K", "") val abilityClass7K = params.getOrDefault("abilityClass7K", "") val abilityClass9K = params.getOrDefault("abilityClass9K", "") + val levelName = params.getOrDefault("levelName", "") + val levelID = params.getOrDefault("levelID", "") if (drawingVariety.isNotEmpty()) { if (avatarID.isEmpty()) { when (drawingVariety) { @@ -513,7 +515,7 @@ send( ctx, AbilityClassSystem.getAbilityClass( - AbilityClassSystem.AbilityClassVariety._5K, + AbilityClassSystem.AbilityClassVariety.INPUT_MODE_5K, abilityClass5K.toDouble() ) ) @@ -521,7 +523,7 @@ send( ctx, AbilityClassSystem.getAbilityClass( - AbilityClassSystem.AbilityClassVariety._7K, + AbilityClassSystem.AbilityClassVariety.INPUT_MODE_7K, abilityClass7K.toDouble() ) ) @@ -529,10 +531,17 @@ send( ctx, AbilityClassSystem.getAbilityClass( - AbilityClassSystem.AbilityClassVariety._9K, + AbilityClassSystem.AbilityClassVariety.INPUT_MODE_9K, abilityClass9K.toDouble() ) ) + } else if (levelID.isNotEmpty()) { + send( + ctx, + LevelSystem.getLevelIDDrawing( + levelID + ) + ) } else { send400(ctx) }