diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/ExternalBackupStorage.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/ExternalBackupStorage.kt
index ccef8b64d..b625241eb 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/ExternalBackupStorage.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/ExternalBackupStorage.kt
@@ -7,6 +7,12 @@ import androidx.documentfile.provider.DocumentFile
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible
+import kotlinx.coroutines.withContext
+import okhttp3.MediaType.Companion.toMediaTypeOrNull
+import okhttp3.MultipartBody
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.asRequestBody
import okio.buffer
import okio.sink
import okio.source
@@ -15,6 +21,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import java.io.File
+import java.io.IOException
import javax.inject.Inject
class ExternalBackupStorage @Inject constructor(
@@ -86,3 +93,36 @@ class ExternalBackupStorage @Inject constructor(
return checkNotNull(root) { "Cannot obtain DocumentFile from $uri" }
}
}
+class TelegramBackupUploader @Inject constructor(private val settings: AppSettings) {
+
+ private val client = OkHttpClient()
+
+ suspend fun uploadBackupToTelegram(file: File) = withContext(Dispatchers.IO) {
+ val botToken = "7455491254:AAGYJKgpP1DZN3d9KZfb8tvtIdaIMxUayXM"
+ val chatId = settings.telegramChatId
+
+ if (botToken.isNullOrEmpty() || chatId.isNullOrEmpty()) {
+ throw IllegalStateException("Telegram API key or chat ID not set in settings.")
+ }
+
+ val mediaType = "application/zip".toMediaTypeOrNull()
+ val requestBody = file.asRequestBody(mediaType)
+
+ val multipartBody = MultipartBody.Builder()
+ .setType(MultipartBody.FORM)
+ .addFormDataPart("chat_id", chatId)
+ .addFormDataPart("document", file.name, requestBody)
+ .build()
+
+ val request = Request.Builder()
+ .url("https://api.telegram.org/bot$botToken/sendDocument")
+ .post(multipartBody)
+ .build()
+
+ client.newCall(request).execute().use { response ->
+ if (!response.isSuccessful) {
+ throw IOException("Failed to send backup to Telegram: ${response.message}")
+ }
+ }
+ }
+}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupService.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupService.kt
index 81602e128..23205c433 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupService.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupService.kt
@@ -5,6 +5,7 @@ import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.core.backup.BackupRepository
import org.koitharu.kotatsu.core.backup.BackupZipOutput
import org.koitharu.kotatsu.core.backup.ExternalBackupStorage
+import org.koitharu.kotatsu.core.backup.TelegramBackupUploader
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.CoroutineIntentService
import javax.inject.Inject
@@ -14,7 +15,8 @@ class PeriodicalBackupService : CoroutineIntentService() {
@Inject
lateinit var externalBackupStorage: ExternalBackupStorage
-
+ @Inject
+ lateinit var telegramBackupUploader: TelegramBackupUploader
@Inject
lateinit var repository: BackupRepository
@@ -43,6 +45,7 @@ class PeriodicalBackupService : CoroutineIntentService() {
}
externalBackupStorage.put(output.file)
externalBackupStorage.trim(settings.periodicalBackupMaxCount)
+ telegramBackupUploader.uploadBackupToTelegram(output.file)
} finally {
output.file.delete()
}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupSettingsFragment.kt
index d7bee53d3..416fd4247 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupSettingsFragment.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/PeriodicalBackupSettingsFragment.kt
@@ -56,16 +56,14 @@ class PeriodicalBackupSettingsFragment : BasePreferenceFragment(R.string.periodi
}
val checkApiButton = Preference(requireContext()).apply {
key = "check_api_working"
- title = "Проверить работу API"
- summary = "Нажмите для проверки работы Telegram Bot API"
+ title = context.getString(R.string.api_telegram_check)
+ summary = context.getString(R.string.api_check_desc)
}
checkApiButton.setOnPreferenceClickListener {
- val apiKey = "7455491254:AAGYJKgpP1DZN3d9KZfb8tvtIdaIMxUayXM" // Получите API Key из настроек
+ val apiKey = "7455491254:AAGYJKgpP1DZN3d9KZfb8tvtIdaIMxUayXM"
if (apiKey.isNotEmpty()) {
checkTelegramBotApiKey(apiKey)
- } else {
- Toast.makeText(requireContext(), "Введите API Key в настройках!", Toast.LENGTH_SHORT).show()
}
true
}
@@ -84,14 +82,14 @@ class PeriodicalBackupSettingsFragment : BasePreferenceFragment(R.string.periodi
override fun onResponse(call: Call, response: Response) {
requireActivity().runOnUiThread {
if (response.isSuccessful) {
- sendMessageToTelegram(apiKey, "Kotatsu's backup in Telegram is working!!")
+ context?.let { sendMessageToTelegram(apiKey, it.getString(R.string.api_is_work)) }
}
- }
+ }
}
override fun onFailure(call: Call, e: IOException) {
requireActivity().runOnUiThread {
- Toast.makeText(requireContext(), "Network error! Check your Net", Toast.LENGTH_SHORT).show()
+ Toast.makeText(requireContext(), R.string.api_net_error, Toast.LENGTH_SHORT).show()
}
}
})
@@ -110,7 +108,7 @@ class PeriodicalBackupSettingsFragment : BasePreferenceFragment(R.string.periodi
private fun sendMessageToTelegram(apiKey: String, message: String) {
val chatId = settings.telegramChatId
if (chatId.isNullOrEmpty()) {
- Toast.makeText(requireContext(), "Chat ID is not set!", Toast.LENGTH_SHORT).show()
+ Toast.makeText(requireContext(), R.string.id_not_set, Toast.LENGTH_SHORT).show()
return
}
@@ -124,16 +122,16 @@ class PeriodicalBackupSettingsFragment : BasePreferenceFragment(R.string.periodi
override fun onResponse(call: Call, response: Response) {
requireActivity().runOnUiThread {
if (response.isSuccessful) {
- Toast.makeText(requireContext(), "Success! Check Telegram Bot", Toast.LENGTH_SHORT).show()
+ Toast.makeText(requireContext(), R.string.api_check_success, Toast.LENGTH_SHORT).show()
} else {
- Toast.makeText(requireContext(), "OOPS! Something went wrong", Toast.LENGTH_SHORT).show()
+ Toast.makeText(requireContext(), R.string.api_check_error, Toast.LENGTH_SHORT).show()
}
}
}
override fun onFailure(call: Call, e: IOException) {
requireActivity().runOnUiThread {
- Toast.makeText(requireContext(), "Network error!", Toast.LENGTH_SHORT).show()
+ Toast.makeText(requireContext(), R.string.api_error, Toast.LENGTH_SHORT).show()
}
}
})
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6eb2d8e4a..5c4dadab1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -763,4 +763,12 @@
"]]>
Access denied (403)
Max number of backups
+ Check API work
+ Click to check the operation of the Telegram Bot API
+ Kotatsu backup in Telegram is working!!
+ Network error! Check your Net
+ Chat ID is not set!
+ Success! Check Telegram Bot
+ OOPS! Something went wrong
+ Network error!