4 files changed
+64
-64
No files matched your search
@@ -114,15 +114,12 @@ object ImageBytesResolver {
|
|||||||
}.getOrElse { e -> Result.Error(e.message ?: "Could not download image") }
|
}.getOrElse { e -> Result.Error(e.message ?: "Could not download image") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Image-only view of the shared MIME table: anything that isn't `image/` saves as `.img`. */
|
||||||
fun extensionForMime(mime: String): String =
|
fun extensionForMime(mime: String): String =
|
||||||
when (mime.substringBefore(';').trim().lowercase()) {
|
if (mime.trim().startsWith("image/", ignoreCase = true)) {
|
||||||
"image/jpeg", "image/jpg" -> "jpg"
|
com.m57.hermescontrol.ui.chat
|
||||||
"image/png" -> "png"
|
.extensionForMime(mime)
|
||||||
"image/gif" -> "gif"
|
} else {
|
||||||
"image/webp" -> "webp"
|
"img"
|
||||||
"image/bmp" -> "bmp"
|
|
||||||
"image/heic", "image/heif" -> "heic"
|
|
||||||
"image/svg+xml" -> "svg"
|
|
||||||
else -> "img"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,67 +140,41 @@ fun normalizeFrameworkMime(mime: String?): String =
|
|||||||
?.takeIf { it.isNotBlank() }
|
?.takeIf { it.isNotBlank() }
|
||||||
?: "application/octet-stream"
|
?: "application/octet-stream"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIME aliases and preferred extensions that [MEDIA_BY_EXT] can't express
|
||||||
|
* (it's keyed by extension, so `image/jpeg` would otherwise resolve to its
|
||||||
|
* first entry, `jpeg`). HEIC is save-only here: it isn't classified as inline media.
|
||||||
|
*/
|
||||||
|
private val EXT_BY_MIME_ALIAS: Map<String, String> =
|
||||||
|
mapOf(
|
||||||
|
"image/jpeg" to "jpg",
|
||||||
|
"image/jpg" to "jpg",
|
||||||
|
"image/heic" to "heic",
|
||||||
|
"image/heif" to "heic",
|
||||||
|
"audio/mp3" to "mp3",
|
||||||
|
"audio/x-m4a" to "m4a",
|
||||||
|
"audio/x-wav" to "wav",
|
||||||
|
"audio/wave" to "wav",
|
||||||
|
"application/x-flac" to "flac",
|
||||||
|
"application/ogg" to "ogg",
|
||||||
|
)
|
||||||
|
|
||||||
/** Returns the canonical file extension for a given MIME type. */
|
/** Returns the canonical file extension for a given MIME type. */
|
||||||
fun extensionForMime(mime: String): String {
|
fun extensionForMime(mime: String): String {
|
||||||
val clean = mime.substringBefore(';').trim().lowercase()
|
val clean = mime.substringBefore(';').trim().lowercase()
|
||||||
for ((ext, pair) in MEDIA_BY_EXT) {
|
EXT_BY_MIME_ALIAS[clean]?.let { return it }
|
||||||
if (pair.second
|
MEDIA_BY_EXT.entries
|
||||||
|
.firstOrNull { (_, pair) ->
|
||||||
|
pair.second
|
||||||
.substringBefore(';')
|
.substringBefore(';')
|
||||||
.trim()
|
.trim()
|
||||||
.lowercase() == clean
|
.lowercase() == clean
|
||||||
) {
|
}?.let { return it.key }
|
||||||
return ext
|
return when {
|
||||||
}
|
clean.startsWith("video/") -> "mp4"
|
||||||
}
|
clean.startsWith("audio/") -> "mp3"
|
||||||
return when (clean) {
|
clean.startsWith("image/") -> "img"
|
||||||
"image/jpeg", "image/jpg" -> {
|
else -> "bin"
|
||||||
"jpg"
|
|
||||||
}
|
|
||||||
|
|
||||||
"video/mp4" -> {
|
|
||||||
"mp4"
|
|
||||||
}
|
|
||||||
|
|
||||||
"video/x-matroska" -> {
|
|
||||||
"mkv"
|
|
||||||
}
|
|
||||||
|
|
||||||
"video/quicktime" -> {
|
|
||||||
"mov"
|
|
||||||
}
|
|
||||||
|
|
||||||
"audio/mpeg", "audio/mp3" -> {
|
|
||||||
"mp3"
|
|
||||||
}
|
|
||||||
|
|
||||||
"audio/mp4", "audio/x-m4a" -> {
|
|
||||||
"m4a"
|
|
||||||
}
|
|
||||||
|
|
||||||
"audio/wav", "audio/x-wav", "audio/wave" -> {
|
|
||||||
"wav"
|
|
||||||
}
|
|
||||||
|
|
||||||
"audio/flac", "application/x-flac" -> {
|
|
||||||
"flac"
|
|
||||||
}
|
|
||||||
|
|
||||||
"audio/ogg", "application/ogg" -> {
|
|
||||||
"ogg"
|
|
||||||
}
|
|
||||||
|
|
||||||
"audio/aac" -> {
|
|
||||||
"aac"
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
when {
|
|
||||||
clean.startsWith("video/") -> "mp4"
|
|
||||||
clean.startsWith("audio/") -> "mp3"
|
|
||||||
clean.startsWith("image/") -> "img"
|
|
||||||
else -> "bin"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ class ImageBytesResolverTest {
|
|||||||
assertEquals("heic", ImageBytesResolver.extensionForMime("image/heic"))
|
assertEquals("heic", ImageBytesResolver.extensionForMime("image/heic"))
|
||||||
assertEquals("svg", ImageBytesResolver.extensionForMime("image/svg+xml"))
|
assertEquals("svg", ImageBytesResolver.extensionForMime("image/svg+xml"))
|
||||||
assertEquals("img", ImageBytesResolver.extensionForMime("image/unknown"))
|
assertEquals("img", ImageBytesResolver.extensionForMime("image/unknown"))
|
||||||
|
assertEquals("heic", ImageBytesResolver.extensionForMime("image/heif"))
|
||||||
|
assertEquals("bmp", ImageBytesResolver.extensionForMime("image/bmp"))
|
||||||
|
// Non-image content types stay `.img`, not `.bin`/`.pdf`.
|
||||||
|
assertEquals("img", ImageBytesResolver.extensionForMime("application/pdf"))
|
||||||
|
assertEquals("img", ImageBytesResolver.extensionForMime("text/html"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -30,6 +30,30 @@ class MediaTypesTest {
|
|||||||
assertEquals("application/octet-stream", mediaMimeForPath("/tmp/x.weird"))
|
assertEquals("application/octet-stream", mediaMimeForPath("/tmp/x.weird"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `extension for mime uses one table plus aliases`() {
|
||||||
|
// Table entries, including params and case.
|
||||||
|
assertEquals("png", extensionForMime("image/png"))
|
||||||
|
assertEquals("png", extensionForMime(" IMAGE/PNG; charset=binary"))
|
||||||
|
assertEquals("ogg", extensionForMime("audio/ogg; codecs=opus"))
|
||||||
|
assertEquals("mkv", extensionForMime("video/x-matroska"))
|
||||||
|
assertEquals("pdf", extensionForMime("application/pdf"))
|
||||||
|
// Aliases win over first-table-match.
|
||||||
|
assertEquals("jpg", extensionForMime("image/jpeg"))
|
||||||
|
assertEquals("jpg", extensionForMime("image/jpg"))
|
||||||
|
assertEquals("heic", extensionForMime("image/heif"))
|
||||||
|
assertEquals("mp3", extensionForMime("audio/mp3"))
|
||||||
|
assertEquals("m4a", extensionForMime("audio/x-m4a"))
|
||||||
|
assertEquals("wav", extensionForMime("audio/wave"))
|
||||||
|
assertEquals("flac", extensionForMime("application/x-flac"))
|
||||||
|
assertEquals("ogg", extensionForMime("application/ogg"))
|
||||||
|
// Family fallbacks.
|
||||||
|
assertEquals("mp4", extensionForMime("video/unknown"))
|
||||||
|
assertEquals("mp3", extensionForMime("audio/unknown"))
|
||||||
|
assertEquals("img", extensionForMime("image/unknown"))
|
||||||
|
assertEquals("bin", extensionForMime("application/unknown"))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `name extraction handles urls and paths`() {
|
fun `name extraction handles urls and paths`() {
|
||||||
assertEquals("report.pdf", mediaNameFromPath("https://gw/api/files/download?path=%2Ftmp%2Freport.pdf"))
|
assertEquals("report.pdf", mediaNameFromPath("https://gw/api/files/download?path=%2Ftmp%2Freport.pdf"))
|
||||||
|
|||||||
Reference in new issue
Block a user