Initial commit: PaperScan — lokale Android documentscanner voor Paperless-ngx
Native Kotlin/Compose app met CameraX + OpenCV randdetectie/perspectiefcorrectie, multi-page PDF-export, en Paperless-ngx upload (of Android deelmenu). Alles lokaal. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package eu.geyskens.pdfscan.paperless
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Minimal Paperless-ngx REST client. Talks only to the user-configured, self-hosted
|
||||
* instance. The token is sent as an `Authorization: Token …` header over the connection
|
||||
* the user set up (HTTPS strongly recommended — see SettingsScreen guidance).
|
||||
*/
|
||||
class PaperlessClient(
|
||||
private val baseUrl: String,
|
||||
private val token: String,
|
||||
) {
|
||||
private val client = OkHttpClient.Builder()
|
||||
.connectTimeout(15, TimeUnit.SECONDS)
|
||||
.writeTimeout(60, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
private val root = baseUrl.trim().trimEnd('/')
|
||||
|
||||
sealed interface Result {
|
||||
data object Success : Result
|
||||
data class Failure(val message: String) : Result
|
||||
}
|
||||
|
||||
/** Verifies the URL + token by hitting an authenticated endpoint. */
|
||||
suspend fun testConnection(): Result = withContext(Dispatchers.IO) {
|
||||
val request = Request.Builder()
|
||||
.url("$root/api/documents/?page_size=1")
|
||||
.header("Authorization", "Token $token")
|
||||
.header("Accept", "application/json")
|
||||
.get()
|
||||
.build()
|
||||
runCatching {
|
||||
client.newCall(request).execute().use { resp ->
|
||||
when {
|
||||
resp.isSuccessful -> Result.Success
|
||||
resp.code == 401 || resp.code == 403 -> Result.Failure("Ongeldig token (${resp.code}).")
|
||||
else -> Result.Failure("Server antwoordde met ${resp.code}.")
|
||||
}
|
||||
}
|
||||
}.getOrElse { Result.Failure(it.message ?: "Verbinding mislukt.") }
|
||||
}
|
||||
|
||||
/** Uploads a PDF to the Paperless consume/inbox pipeline. */
|
||||
suspend fun upload(pdf: File, title: String): Result = withContext(Dispatchers.IO) {
|
||||
val body = MultipartBody.Builder()
|
||||
.setType(MultipartBody.FORM)
|
||||
.addFormDataPart("title", title)
|
||||
.addFormDataPart(
|
||||
"document", "$title.pdf",
|
||||
pdf.asRequestBody("application/pdf".toMediaType())
|
||||
)
|
||||
.build()
|
||||
val request = Request.Builder()
|
||||
.url("$root/api/documents/post_document/")
|
||||
.header("Authorization", "Token $token")
|
||||
.post(body)
|
||||
.build()
|
||||
runCatching {
|
||||
client.newCall(request).execute().use { resp ->
|
||||
if (resp.isSuccessful) Result.Success
|
||||
else Result.Failure("Upload mislukt: ${resp.code} ${resp.message}")
|
||||
}
|
||||
}.getOrElse { Result.Failure(it.message ?: "Upload mislukt.") }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user