Remove koreader sync server address from settings (#1807)

Should have been done with 4dbd9d70d2
This commit is contained in:
schroda
2025-12-06 18:38:45 +01:00
committed by GitHub
parent 39cae6cc2d
commit 3b36ec550d
4 changed files with 71 additions and 31 deletions

View File

@@ -688,12 +688,22 @@ class ServerConfig(
defaultValue = "suwayomi-server-api", defaultValue = "suwayomi-server-api",
) )
val koreaderSyncServerUrl: MutableStateFlow<String> by StringSetting( @Deprecated("Moved to preference store. User is supposed to use a login/logout mutation")
val koreaderSyncServerUrl: MutableStateFlow<String> by MigratedConfigValue(
protoNumber = 59, protoNumber = 59,
group = SettingGroup.KOREADER_SYNC, group = SettingGroup.KOREADER_SYNC,
privacySafe = true, privacySafe = true,
defaultValue = "https://sync.koreader.rocks/", defaultValue = "https://sync.koreader.rocks/",
description = "KOReader Sync Server URL. Public alternative: https://kosync.ak-team.com:3042/", deprecated = SettingsRegistry.SettingDeprecated(
replaceWith = "MOVE TO PREFERENCES",
message = "Moved to preference store. User is supposed to use a login/logout mutation",
migrateConfig = { value, config ->
val koreaderPreferences = application.getSharedPreferences("koreader_sync", Context.MODE_PRIVATE)
koreaderPreferences.edit().putString("server_address", value.unwrapped() as? String).apply()
config
}
),
) )
@Deprecated("Moved to preference store. User is supposed to use a login/logout mutation") @Deprecated("Moved to preference store. User is supposed to use a login/logout mutation")

View File

@@ -19,6 +19,7 @@ import java.util.concurrent.CompletableFuture
class KoreaderSyncMutation { class KoreaderSyncMutation {
data class ConnectKoSyncAccountInput( data class ConnectKoSyncAccountInput(
val clientMutationId: String? = null, val clientMutationId: String? = null,
val serverAddress: String,
val username: String, val username: String,
val password: String, val password: String,
) )
@@ -26,7 +27,7 @@ class KoreaderSyncMutation {
@RequireAuth @RequireAuth
fun connectKoSyncAccount(input: ConnectKoSyncAccountInput): CompletableFuture<KoSyncConnectPayload> = fun connectKoSyncAccount(input: ConnectKoSyncAccountInput): CompletableFuture<KoSyncConnectPayload> =
future { future {
val (message, status) = KoreaderSyncService.connect(input.username, input.password) val (message, status) = KoreaderSyncService.connect(input.serverAddress, input.username, input.password)
KoSyncConnectPayload( KoSyncConnectPayload(
clientMutationId = input.clientMutationId, clientMutationId = input.clientMutationId,
@@ -45,7 +46,7 @@ class KoreaderSyncMutation {
KoreaderSyncService.logout() KoreaderSyncService.logout()
LogoutKoSyncAccountPayload( LogoutKoSyncAccountPayload(
clientMutationId = input.clientMutationId, clientMutationId = input.clientMutationId,
status = KoSyncStatusPayload(isLoggedIn = false, username = null), status = KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null),
) )
} }

View File

@@ -2,6 +2,7 @@ package suwayomi.tachidesk.graphql.types
data class KoSyncStatusPayload( data class KoSyncStatusPayload(
val isLoggedIn: Boolean, val isLoggedIn: Boolean,
val serverAddress: String?,
val username: String?, val username: String?,
) )

View File

@@ -34,6 +34,7 @@ import kotlin.math.abs
object KoreaderSyncService { object KoreaderSyncService {
private val preferences = Injekt.get<Application>().getSharedPreferences("koreader_sync", Context.MODE_PRIVATE) private val preferences = Injekt.get<Application>().getSharedPreferences("koreader_sync", Context.MODE_PRIVATE)
private const val SERVER_ADDRESS_KEY = "server_address"
private const val USERNAME_KEY = "username" private const val USERNAME_KEY = "username"
private const val USERKEY_KEY = "user_key" private const val USERKEY_KEY = "user_key"
private const val DEVICE_ID_KEY = "client_id" private const val DEVICE_ID_KEY = "client_id"
@@ -179,6 +180,7 @@ object KoreaderSyncService {
} }
private suspend fun register( private suspend fun register(
serverAddress: String,
username: String, username: String,
userkey: String, userkey: String,
): AuthResult { ): AuthResult {
@@ -188,7 +190,7 @@ object KoreaderSyncService {
put("password", userkey) put("password", userkey)
} }
val request = val request =
buildRequest("${serverConfig.koreaderSyncServerUrl.value.removeSuffix("/")}/users/create") { buildRequest("${serverAddress.removeSuffix("/")}/users/create") {
post(payload.toString().toRequestBody("application/json".toMediaType())) post(payload.toString().toRequestBody("application/json".toMediaType()))
} }
@@ -216,11 +218,12 @@ object KoreaderSyncService {
} }
private suspend fun authorize( private suspend fun authorize(
serverAddress: String,
username: String, username: String,
userkey: String, userkey: String,
): AuthResult { ): AuthResult {
val request = val request =
buildRequest("${serverConfig.koreaderSyncServerUrl.value.removeSuffix("/")}/users/auth") { buildRequest("${serverAddress.removeSuffix("/")}/users/auth") {
get() get()
addHeader("x-auth-user", username) addHeader("x-auth-user", username)
addHeader("x-auth-key", userkey) addHeader("x-auth-key", userkey)
@@ -241,61 +244,88 @@ object KoreaderSyncService {
} }
} }
private fun getCredentials(): Pair<String, String> { private fun getCredentials(): Triple<String, String, String> {
val serverAddress = preferences.getString(SERVER_ADDRESS_KEY, "https://sync.koreader.rocks/")!!
val username = preferences.getString(USERNAME_KEY, "")!! val username = preferences.getString(USERNAME_KEY, "")!!
val userkey = preferences.getString(USERKEY_KEY, "")!! val userkey = preferences.getString(USERKEY_KEY, "")!!
return Pair(username, userkey) return Triple(serverAddress, username, userkey)
} }
private fun setCredentials( private fun setCredentials(
serverAddress: String,
username: String, username: String,
userkey: String, userkey: String,
) { ) {
preferences preferences
.edit() .edit()
.putString(SERVER_ADDRESS_KEY, serverAddress)
.putString(USERNAME_KEY, username) .putString(USERNAME_KEY, username)
.putString(USERKEY_KEY, userkey) .putString(USERKEY_KEY, userkey)
.apply() .apply()
} }
private fun clearCredentials() {
preferences.edit().clear().apply()
}
suspend fun connect( suspend fun connect(
serverAddress: String,
username: String, username: String,
password: String, password: String,
): ConnectResult { ): ConnectResult {
val userkey = Hash.md5(password) val userkey = Hash.md5(password)
val authResult = authorize(username, userkey) val authResult = authorize(serverAddress, username, userkey)
if (authResult.success) { if (authResult.success) {
setCredentials(username, userkey) setCredentials(serverAddress, username, userkey)
return ConnectResult("Login successful.", KoSyncStatusPayload(isLoggedIn = true, username = username)) return ConnectResult(
"Login successful.",
KoSyncStatusPayload(isLoggedIn = true, serverAddress = serverAddress, username = username),
)
} }
if (authResult.isUserNotFoundError) { if (authResult.isUserNotFoundError) {
logger.info { "[KOSYNC CONNECT] Authorization failed, attempting to register new user." } logger.info { "[KOSYNC CONNECT] Authorization failed, attempting to register new user." }
val registerResult = register(username, userkey) val registerResult = register(serverAddress, username, userkey)
return if (registerResult.success) { return if (registerResult.success) {
setCredentials(username, userkey) setCredentials(serverAddress, username, userkey)
ConnectResult("Registration successful.", KoSyncStatusPayload(isLoggedIn = true, username = username)) ConnectResult(
"Registration successful.",
KoSyncStatusPayload(isLoggedIn = true, serverAddress = serverAddress, username = username),
)
} else { } else {
ConnectResult(registerResult.message ?: "Registration failed.", KoSyncStatusPayload(isLoggedIn = false, username = null)) ConnectResult(
registerResult.message ?: "Registration failed.",
KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null),
)
} }
} }
return ConnectResult(authResult.message ?: "Authentication failed.", KoSyncStatusPayload(isLoggedIn = false, username = null)) return ConnectResult(
authResult.message ?: "Authentication failed.",
KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null),
)
} }
suspend fun logout() { fun logout() {
setCredentials("", "") clearCredentials()
} }
suspend fun getStatus(): KoSyncStatusPayload { suspend fun getStatus(): KoSyncStatusPayload {
val (username, userkey) = getCredentials() val (serverAddress, username, userkey) = getCredentials()
if (username.isBlank() || userkey.isBlank()) { if (username.isBlank() || userkey.isBlank()) {
return KoSyncStatusPayload(isLoggedIn = false, username = null) return KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null)
}
val authResult = authorize(serverAddress, username, userkey)
return if (authResult.success) {
KoSyncStatusPayload(isLoggedIn = true, serverAddress = serverAddress, username = username)
} else {
KoSyncStatusPayload(isLoggedIn = false, serverAddress = null, username = null)
} }
val authResult = authorize(username, userkey)
return KoSyncStatusPayload(isLoggedIn = authResult.success, username = if (authResult.success) username else null)
} }
suspend fun pushProgress(chapterId: Int) { suspend fun pushProgress(chapterId: Int) {
@@ -309,8 +339,8 @@ object KoreaderSyncService {
return return
} }
val (username, userkey) = getCredentials() val (serverAddress, username, userkey) = getCredentials()
if (username.isBlank() || userkey.isBlank()) return if (serverAddress.isBlank() || username.isBlank() || userkey.isBlank()) return
val chapterHash = getOrGenerateChapterHash(chapterId) val chapterHash = getOrGenerateChapterHash(chapterId)
if (chapterHash.isNullOrBlank()) { if (chapterHash.isNullOrBlank()) {
@@ -350,7 +380,7 @@ object KoreaderSyncService {
val requestBody = json.encodeToString(KoreaderProgressPayload.serializer(), payload) val requestBody = json.encodeToString(KoreaderProgressPayload.serializer(), payload)
val request = val request =
buildRequest("${serverConfig.koreaderSyncServerUrl.value.removeSuffix("/")}/syncs/progress") { buildRequest("${serverAddress.removeSuffix("/")}/syncs/progress") {
put(requestBody.toRequestBody("application/json".toMediaType())) put(requestBody.toRequestBody("application/json".toMediaType()))
addHeader("x-auth-user", username) addHeader("x-auth-user", username)
addHeader("x-auth-key", userkey) addHeader("x-auth-key", userkey)
@@ -383,8 +413,8 @@ object KoreaderSyncService {
return null return null
} }
val (username, userkey) = getCredentials() val (serverAddress, username, userkey) = getCredentials()
if (username.isBlank() || userkey.isBlank()) return null if (serverAddress.isBlank() || username.isBlank() || userkey.isBlank()) return null
val chapterHash = getOrGenerateChapterHash(chapterId) val chapterHash = getOrGenerateChapterHash(chapterId)
if (chapterHash.isNullOrBlank()) { if (chapterHash.isNullOrBlank()) {
@@ -394,7 +424,7 @@ object KoreaderSyncService {
try { try {
val request = val request =
buildRequest("${serverConfig.koreaderSyncServerUrl.value.removeSuffix("/")}/syncs/progress/$chapterHash") { buildRequest("${serverAddress.removeSuffix("/")}/syncs/progress/$chapterHash") {
get() get()
addHeader("x-auth-user", username) addHeader("x-auth-user", username)
addHeader("x-auth-key", userkey) addHeader("x-auth-key", userkey)
@@ -434,9 +464,7 @@ object KoreaderSyncService {
} }
val localPercentage = val localPercentage =
if (localProgress?.pageCount ?: 0 > if ((localProgress?.pageCount ?: 0) > 0) {
0
) {
(localProgress!!.lastPageRead + 1).toFloat() / localProgress.pageCount (localProgress!!.lastPageRead + 1).toFloat() / localProgress.pageCount
} else { } else {
0f 0f