feat: add StrippingResult data class to MetadataStripper

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
davotoula
2026-03-18 10:25:50 +01:00
parent 72158e8fc2
commit f9176fc3fb
@@ -33,6 +33,11 @@ import com.vitorpamplona.quartz.utils.Log
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import java.io.File import java.io.File
data class StrippingResult(
val uri: Uri,
val stripped: Boolean,
)
class MetadataStripper { class MetadataStripper {
companion object { companion object {
private const val REMUX_BUFFER_SIZE = 8 * 1024 * 1024 private const val REMUX_BUFFER_SIZE = 8 * 1024 * 1024
@@ -104,7 +109,7 @@ class MetadataStripper {
fun stripImageMetadata( fun stripImageMetadata(
uri: Uri, uri: Uri,
context: Context, context: Context,
): Uri { ): StrippingResult {
return try { return try {
val tempFile = File.createTempFile("stripped_", ".jpg", context.cacheDir) val tempFile = File.createTempFile("stripped_", ".jpg", context.cacheDir)
@@ -112,7 +117,7 @@ class MetadataStripper {
tempFile.outputStream().use { output -> tempFile.outputStream().use { output ->
input.copyTo(output) input.copyTo(output)
} }
} ?: return uri } ?: return StrippingResult(uri, false)
val exif = ExifInterface(tempFile.absolutePath) val exif = ExifInterface(tempFile.absolutePath)
for (tag in SENSITIVE_EXIF_TAGS) { for (tag in SENSITIVE_EXIF_TAGS) {
@@ -121,25 +126,25 @@ class MetadataStripper {
exif.saveAttributes() exif.saveAttributes()
Log.d("MetadataStripper", "Stripped EXIF metadata from image") Log.d("MetadataStripper", "Stripped EXIF metadata from image")
tempFile.toUri() StrippingResult(tempFile.toUri(), true)
} catch (e: Exception) { } catch (e: Exception) {
if (e is CancellationException) throw e if (e is CancellationException) throw e
Log.d("MetadataStripper", "Failed to strip image metadata: ${e.message}") Log.d("MetadataStripper", "Failed to strip image metadata: ${e.message}")
uri StrippingResult(uri, false)
} }
} }
fun stripVideoMetadata( fun stripVideoMetadata(
uri: Uri, uri: Uri,
context: Context, context: Context,
): Uri { ): StrippingResult {
return try { return try {
val tempInputFile = File.createTempFile("video_input_", ".mp4", context.cacheDir) val tempInputFile = File.createTempFile("video_input_", ".mp4", context.cacheDir)
context.contentResolver.openInputStream(uri)?.use { input -> context.contentResolver.openInputStream(uri)?.use { input ->
tempInputFile.outputStream().use { output -> tempInputFile.outputStream().use { output ->
input.copyTo(output) input.copyTo(output)
} }
} ?: return uri } ?: return StrippingResult(uri, false)
val tempOutputFile = File.createTempFile("stripped_video_", ".mp4", context.cacheDir) val tempOutputFile = File.createTempFile("stripped_video_", ".mp4", context.cacheDir)
@@ -150,7 +155,7 @@ class MetadataStripper {
try { try {
extractor.setDataSource(tempInputFile.absolutePath) extractor.setDataSource(tempInputFile.absolutePath)
if (extractor.trackCount == 0) return uri if (extractor.trackCount == 0) return StrippingResult(uri, false)
// Note: MediaMuxer may still write a creation timestamp and encoder info into // Note: MediaMuxer may still write a creation timestamp and encoder info into
// the new container. This is not controllable via the Android API and is a // the new container. This is not controllable via the Android API and is a
@@ -211,25 +216,25 @@ class MetadataStripper {
} }
Log.d("MetadataStripper", "Stripped metadata from video") Log.d("MetadataStripper", "Stripped metadata from video")
tempOutputFile.toUri() StrippingResult(tempOutputFile.toUri(), true)
} catch (e: Exception) { } catch (e: Exception) {
if (e is CancellationException) throw e if (e is CancellationException) throw e
Log.d("MetadataStripper", "Failed to strip video metadata: ${e.message}") Log.d("MetadataStripper", "Failed to strip video metadata: ${e.message}")
uri StrippingResult(uri, false)
} }
} }
fun stripAudioMetadata( fun stripAudioMetadata(
uri: Uri, uri: Uri,
context: Context, context: Context,
): Uri { ): StrippingResult {
return try { return try {
val tempInputFile = File.createTempFile("audio_input_", ".tmp", context.cacheDir) val tempInputFile = File.createTempFile("audio_input_", ".tmp", context.cacheDir)
context.contentResolver.openInputStream(uri)?.use { input -> context.contentResolver.openInputStream(uri)?.use { input ->
tempInputFile.outputStream().use { output -> tempInputFile.outputStream().use { output ->
input.copyTo(output) input.copyTo(output)
} }
} ?: return uri } ?: return StrippingResult(uri, false)
val extractor = MediaExtractor() val extractor = MediaExtractor()
var muxer: MediaMuxer? = null var muxer: MediaMuxer? = null
@@ -239,7 +244,7 @@ class MetadataStripper {
try { try {
extractor.setDataSource(tempInputFile.absolutePath) extractor.setDataSource(tempInputFile.absolutePath)
if (extractor.trackCount == 0) return uri if (extractor.trackCount == 0) return StrippingResult(uri, false)
val format = extractor.getTrackFormat(0) val format = extractor.getTrackFormat(0)
val mime = format.getString(MediaFormat.KEY_MIME) ?: "" val mime = format.getString(MediaFormat.KEY_MIME) ?: ""
@@ -285,11 +290,11 @@ class MetadataStripper {
} }
Log.d("MetadataStripper", "Stripped metadata from audio") Log.d("MetadataStripper", "Stripped metadata from audio")
tempOutputFile!!.toUri() StrippingResult(tempOutputFile!!.toUri(), true)
} catch (e: Exception) { } catch (e: Exception) {
if (e is CancellationException) throw e if (e is CancellationException) throw e
Log.d("MetadataStripper", "Failed to strip audio metadata: ${e.message}") Log.d("MetadataStripper", "Failed to strip audio metadata: ${e.message}")
uri StrippingResult(uri, false)
} }
} }
@@ -297,11 +302,11 @@ class MetadataStripper {
uri: Uri, uri: Uri,
mimeType: String?, mimeType: String?,
context: Context, context: Context,
): Uri = ): StrippingResult =
when { when {
mimeType?.startsWith("image/", ignoreCase = true) == true -> stripImageMetadata(uri, context) mimeType?.startsWith("image/", ignoreCase = true) == true -> stripImageMetadata(uri, context)
mimeType?.startsWith("video/", ignoreCase = true) == true -> stripVideoMetadata(uri, context) mimeType?.startsWith("video/", ignoreCase = true) == true -> stripVideoMetadata(uri, context)
mimeType?.startsWith("audio/", ignoreCase = true) == true -> stripAudioMetadata(uri, context) mimeType?.startsWith("audio/", ignoreCase = true) == true -> stripAudioMetadata(uri, context)
else -> uri else -> StrippingResult(uri, false)
} }
} }