fix(api): embedded fonts would not load on windows

Closes: #1877
This commit is contained in:
Gauthier Roebroeck 2025-02-17 18:04:42 +08:00
parent 25dc282fc6
commit 0546deb424
2 changed files with 95 additions and 7 deletions

View file

@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.api.rest
import io.github.oshai.kotlinlogging.KotlinLogging
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import org.apache.commons.io.FilenameUtils
import org.gotson.komga.infrastructure.configuration.KomgaProperties
import org.gotson.komga.infrastructure.swagger.OpenApiConfiguration
import org.gotson.komga.language.contains
@ -45,9 +46,9 @@ class FontsController(
resolver
.getResources("/embeddedFonts/**/*.*")
.filterNot { it.filename == null }
.filter { supportedExtensions.contains(Path(it.uri.toString()).extension, true) }
.filter { supportedExtensions.contains(FilenameUtils.getExtension(it.uri.toString()), true) }
.groupBy {
Path(it.uri.toString()).parent.name
FilenameUtils.getName(FilenameUtils.getPathNoEndSeparator(it.uri.toString()))
}
} catch (e: Exception) {
logger.error(e) { "Could not load embedded fonts" }
@ -96,7 +97,7 @@ class FontsController(
): ResponseEntity<Resource> {
fonts[fontFamily]?.let { resources ->
val resource = resources.firstOrNull { it.filename == fontFile } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
val mediaType = "font/${Path(resource.uri.toString()).extension.lowercase()}"
val mediaType = "font/${FilenameUtils.getExtension(resource.uri.toString()).lowercase()}"
return ResponseEntity
.ok()
.headers {
@ -116,7 +117,7 @@ class FontsController(
@PathVariable fontFamily: String,
): ResponseEntity<Resource> {
fonts[fontFamily]?.let { files ->
val groups = files.groupBy { getFontCharacteristics(Path(it.uri.toString()).name) }
val groups = files.groupBy { getFontCharacteristics(FilenameUtils.getName(it.uri.toString())) }
val css =
groups
@ -142,14 +143,14 @@ class FontsController(
): String {
val srcBlock =
fonts.joinToString(separator = ",", postfix = ";") { resource ->
val path = Path(resource.uri.toString())
val filename = FilenameUtils.getName(resource.uri.toString())
val format =
when (val extension = path.extension.lowercase()) {
when (val extension = FilenameUtils.getExtension(resource.uri.toString()).lowercase()) {
"ttf" -> "truetype"
"otf" -> "opentype"
else -> extension
}
"""url('${path.name}') format('$format')"""
"""url('$filename') format('$format')"""
}
// language=CSS
return """

View file

@ -0,0 +1,87 @@
package org.gotson.komga.interfaces.api.rest
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.HttpHeaders
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
@SpringBootTest
@AutoConfigureMockMvc(printOnlyOnFailure = false)
class FontsControllerTest(
@Autowired private val mockMvc: MockMvc,
) {
@Test
@WithMockCustomUser
fun `when getting font families then the embedded fonts are returned`() {
mockMvc
.get("/api/v1/fonts/families")
.andExpect {
status { isOk() }
jsonPath("$.length()") { value(1) }
jsonPath("$[0]") { value("OpenDyslexic") }
}
}
@Test
@WithMockCustomUser
fun `when getting font file then the content type headers are correct`() {
mockMvc
.get("/api/v1/fonts/resource/OpenDyslexic/OpenDyslexic-Bold.woff")
.andExpect {
status { isOk() }
header {
string(HttpHeaders.CONTENT_TYPE, "font/woff")
}
}
}
@Test
@WithMockCustomUser
fun `when getting font css file then the content is correct`() {
mockMvc
.get("/api/v1/fonts/resource/OpenDyslexic/css")
.andExpect {
status { isOk() }
header {
string(HttpHeaders.CONTENT_TYPE, "text/css")
}
content {
string(
"""
@font-face {
font-family: 'OpenDyslexic';
src: url('OpenDyslexic-Bold-Italic.woff') format('woff'),url('OpenDyslexic-Bold-Italic.woff2') format('woff2');
font-weight: bold;
font-style: italic;
}
@font-face {
font-family: 'OpenDyslexic';
src: url('OpenDyslexic-Bold.woff') format('woff'),url('OpenDyslexic-Bold.woff2') format('woff2');
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: 'OpenDyslexic';
src: url('OpenDyslexic-Italic.woff') format('woff'),url('OpenDyslexic-Italic.woff2') format('woff2');
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: 'OpenDyslexic';
src: url('OpenDyslexic-Regular.woff') format('woff'),url('OpenDyslexic-Regular.woff2') format('woff2');
font-weight: normal;
font-style: normal;
}
""".trimIndent(),
)
}
}
}
}