Skip to content

Commit 5ba2717

Browse files
committed
Add image compressor
1 parent 633ab49 commit 5ba2717

2 files changed

Lines changed: 56 additions & 2 deletions

File tree

build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ dependencies {
2020
implementation("io.ktor:ktor-server-core:${Versions.KTOR}")
2121
implementation("io.ktor:ktor-server-content-negotiation:${Versions.KTOR}")
2222
implementation("io.ktor:ktor-server-auth:${Versions.KTOR}")
23+
implementation("io.ktor:ktor-server-compression:${Versions.KTOR}")
24+
25+
// Compression
26+
implementation("net.coobird:thumbnailator:0.4.20")
2327

2428
// Logging
2529
implementation("ch.qos.logback:logback-classic:${Versions.LOGBACK}")

src/main/kotlin/net/cakeyfox/marisastuff/MarisaStuffServerInstance.kt

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,79 @@
11
package net.cakeyfox.marisastuff
22

3+
import io.ktor.http.ContentType
4+
import io.ktor.http.HttpStatusCode
5+
import io.ktor.http.fromFilePath
36
import io.ktor.serialization.kotlinx.json.*
47
import io.ktor.server.application.*
58
import io.ktor.server.engine.*
69
import io.ktor.server.http.content.*
710
import io.ktor.server.netty.*
11+
import io.ktor.server.plugins.compression.Compression
12+
import io.ktor.server.plugins.compression.deflate
13+
import io.ktor.server.plugins.compression.gzip
14+
import io.ktor.server.plugins.compression.minimumSize
815
import io.ktor.server.plugins.contentnegotiation.*
16+
import io.ktor.server.response.respond
17+
import io.ktor.server.response.respondBytes
18+
import io.ktor.server.response.respondFile
919
import io.ktor.server.routing.*
1020
import net.cakeyfox.marisastuff.config.ServerConfig
21+
import net.coobird.thumbnailator.Thumbnails
22+
import java.io.ByteArrayOutputStream
1123
import java.io.File
1224

1325
class MarisaStuffServerInstance(
1426
config: ServerConfig
1527
) {
1628
companion object {
17-
private const val STUFF_FOLDER = "/opt/marisa-stuff"
29+
private const val STUFF_FOLDER = "C:\\Users\\WinG4merBR\\Downloads"
1830
}
1931

2032
private val server = embeddedServer(Netty, port = config.port) {
2133
install(ContentNegotiation) {
2234
json()
2335
}
2436

37+
install(Compression) {
38+
gzip { priority = 1.0 }
39+
deflate { priority = 10.0; minimumSize(1024) }
40+
}
41+
2542
routing {
26-
staticFiles("/", File(STUFF_FOLDER))
43+
get("/{path...}") {
44+
val path = call.parameters.getAll("path")?.joinToString("/") ?: return@get
45+
val file = File(STUFF_FOLDER, path)
46+
val size = call.request.queryParameters["size"]?.toIntOrNull()
47+
48+
49+
if (!file.exists() || file.isDirectory) {
50+
call.respond(HttpStatusCode.NotFound)
51+
return@get
52+
}
53+
54+
val extension = file.extension.lowercase()
55+
val isImage = extension in listOf("jpg", "jpeg", "png", "webp")
56+
57+
if (isImage && size != null) {
58+
if (size > 2048) return@get call.respond(HttpStatusCode.BadRequest)
59+
60+
val outputStream = ByteArrayOutputStream()
61+
62+
try {
63+
Thumbnails.of(file)
64+
.size(size, size)
65+
.outputFormat(if (extension == "webp") "png" else extension)
66+
.toOutputStream(outputStream)
67+
68+
val contentType = ContentType.fromFilePath(file.path).first()
69+
call.respondBytes(outputStream.toByteArray(), contentType)
70+
} catch (e: Exception) {
71+
call.respond(HttpStatusCode.InternalServerError, "Erro ao processar imagem")
72+
}
73+
} else {
74+
call.respondFile(file)
75+
}
76+
}
2777
}
2878
}
2979

0 commit comments

Comments
 (0)