Browse Source

Track Android video probing and clean rejected cache files

master
evgeny 2 days ago
parent
commit
8e108425ae
  1. 3
      tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/ConversationComposer.kt
  2. 47
      tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt

3
tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/ConversationComposer.kt

@ -62,7 +62,8 @@ fun ConversationComposer(target: ConversationTarget, viewModel: ChatViewModel, o
}
if (pinned == activeTarget) { selected = attachment; sendAsVideo = false; chooseVideo = attachment.video }
else LogManager.addLog("INFO", "Attachment", "picker discarded after target change")
} catch (e: Exception) { LogManager.addLog("ERROR", "Attachment", "picker failed: ${e.message}"); error = "Не удалось открыть вложение" }
} catch (e: CancellationException) { throw e }
catch (e: Exception) { LogManager.addLog("ERROR", "Attachment", "picker failed: ${e.message}"); error = "Не удалось открыть вложение" }
}
}
Column {

47
tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt

@ -320,7 +320,7 @@ class ChatViewModel : ViewModel() {
}
4 -> { if (repo != null) { LogManager.addLog("INFO", "VM", "CHANNEL_UPDATED — refreshChannels"); refreshChannels() } else { LogManager.addLog("WARN", "VM", "CHANNEL_UPDATED skipped — repo is NULL") } }
12 -> LogManager.addLog("INFO", "VM", "service started")
13 -> LogManager.addLog("INFO", "VM", "service stopped")
13 -> { _attachmentPreparations.value = emptyMap(); LogManager.addLog("INFO", "VM", "service stopped") }
16 -> { /* NODEINFO_UPDATED: [node_id:8][presence:1][up:1][best_rtt:2][bgp_rtt:2][bgp_nodes:2] */
if (data == null || data.size < 12) return
val ns = parseNodeStatus(data) ?: return
@ -1024,7 +1024,7 @@ class ChatViewModel : ViewModel() {
}
fun sendAttachment(filePath: String, target: ConversationTarget, name: String = File(filePath).name) {
val r = repo ?: return
val r = repo ?: throw IllegalStateException("Сервис чата остановлен")
if (target is ConversationTarget.Pm) { NativeLib.dmSendFile(target.id, filePath, name); return }
val chId = target.id
val ext = filePath.substringAfterLast('.', "").lowercase()
@ -1057,26 +1057,37 @@ class ChatViewModel : ViewModel() {
}
}
/** Cache-файл передаётся native только после успешного чтения метаданных. */
fun sendVideoMessage(filePath: String, target: ConversationTarget) {
val r = repo ?: return
val job = java.util.UUID.randomUUID().toString()
preparationState(target.nativeId, job, 0)
viewModelScope.launch {
val meta = withContext(Dispatchers.IO) {
var dur = 0; var w = 0; var h = 0
val mmr = MediaMetadataRetriever()
try {
mmr.setDataSource(filePath)
dur = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toIntOrNull() ?: 0
w = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toIntOrNull() ?: 0
h = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toIntOrNull() ?: 0
} catch (e: Exception) {
LogManager.addLog("WARN", "VM", "video metadata failed: ${e.message}")
} finally {
try { mmr.release() } catch (_: Exception) {}
var accepted = false
try {
val r = repo ?: throw IllegalStateException("Сервис чата остановлен")
val meta = withContext(Dispatchers.IO) {
val mmr = MediaMetadataRetriever()
try {
mmr.setDataSource(filePath)
Triple(
mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toIntOrNull() ?: 0,
mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toIntOrNull() ?: 0,
mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toIntOrNull() ?: 0
)
} finally { mmr.release() }
}
accepted = r.sendVideo(target.nativeId, filePath, meta.first, meta.second, meta.third)
if (!accepted) throw IllegalStateException("Некорректное видео или сервис остановлен")
LogManager.addLog("INFO", "VM", "video queued target=${target.nativeId} dur=${meta.first} ${meta.second}x${meta.third}")
} catch (e: kotlinx.coroutines.CancellationException) { throw e }
catch (e: Exception) { LogManager.addLog("ERROR", "VM", "video failed target=${target.nativeId}: ${e.message}") }
finally {
preparationState(target.nativeId, job, if (accepted) 1 else 2)
if (!accepted) withContext(kotlinx.coroutines.NonCancellable + Dispatchers.IO) {
if (!File(filePath).delete() && File(filePath).exists())
LogManager.addLog("ERROR", "VM", "video cache cleanup failed: $filePath")
}
Triple(dur, w, h)
}
LogManager.addLog("INFO", "VM", "sendVideoMessage target=${target.nativeId} dur=${meta.first} ${meta.second}x${meta.third}")
r.sendVideo(target.nativeId, filePath, meta.first, meta.second, meta.third)
}
}

Loading…
Cancel
Save