From 3caa5da34da9a451e6cd99e5e7ae3a66b18a511a Mon Sep 17 00:00:00 2001 From: djaler Date: Sun, 14 Jan 2024 16:31:13 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=BA=D0=BE=D0=BD=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D1=82=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B2=D0=B8=D0=B4=D0=B5=D0=BE?= =?UTF-8?q?=20=D0=B2=20mp4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 + build.gradle.kts | 2 + .../evilbot/handlers/VideoConverterHandler.kt | 59 +++++++++++++++++++ .../evilbot/service/VideoConvertService.kt | 25 ++++++++ .../com/github/djaler/evilbot/utils/Files.kt | 13 ++++ 5 files changed, 102 insertions(+) create mode 100644 src/main/kotlin/com/github/djaler/evilbot/handlers/VideoConverterHandler.kt create mode 100644 src/main/kotlin/com/github/djaler/evilbot/service/VideoConvertService.kt diff --git a/README.md b/README.md index 14203b4a..99321fb3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ ### Распознавание речи :speaking_head: С помощью [VK Cloud Solutions](https://mcs.mail.ru). Бот может распознавать голосовые сообщения. +### Конвертация видео +Бот автоматически сконвертирует видео в mp4 из других форматов + ### Команды :monocle_face: * */statistic* - статистика сообщений юзера в чате; * */top10* - топ 10 спамеров в чате; diff --git a/build.gradle.kts b/build.gradle.kts index 699fbe2e..2bb59f05 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -53,6 +53,8 @@ dependencies { implementation("io.github.resilience4j:resilience4j-kotlin:1.7.1") implementation("io.github.resilience4j:resilience4j-ratelimiter:1.7.1") + + implementation("ws.schild:jave-all-deps:3.4.0") } tasks.withType { diff --git a/src/main/kotlin/com/github/djaler/evilbot/handlers/VideoConverterHandler.kt b/src/main/kotlin/com/github/djaler/evilbot/handlers/VideoConverterHandler.kt new file mode 100644 index 00000000..fdb69ec9 --- /dev/null +++ b/src/main/kotlin/com/github/djaler/evilbot/handlers/VideoConverterHandler.kt @@ -0,0 +1,59 @@ +package com.github.djaler.evilbot.handlers + +import com.github.djaler.evilbot.handlers.base.MessageHandler +import com.github.djaler.evilbot.service.VideoConvertService +import com.github.djaler.evilbot.utils.toTemporaryFile +import dev.inmo.tgbotapi.bot.RequestsExecutor +import dev.inmo.tgbotapi.extensions.api.files.downloadFile +import dev.inmo.tgbotapi.extensions.api.send.media.sendVideo +import dev.inmo.tgbotapi.extensions.api.send.reply +import dev.inmo.tgbotapi.extensions.api.send.withUploadVideoAction +import dev.inmo.tgbotapi.extensions.utils.asContentMessage +import dev.inmo.tgbotapi.extensions.utils.asDocumentContent +import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile +import dev.inmo.tgbotapi.types.message.abstracts.Message +import org.springframework.stereotype.Component +import java.io.File +import java.util.* +import kotlin.io.path.createTempDirectory + +@Component +class VideoConverterHandler( + private val requestExecutor: RequestsExecutor, + private val videoConvertService: VideoConvertService, +) : MessageHandler() { + override suspend fun handleMessage(message: Message): Boolean { + val document = message.asContentMessage()?.content?.asDocumentContent() ?: return false + val mimeType = document.media.mimeType ?: return false + if (mimeType.primaryType != "video") { + return false + } + if (mimeType.subType == "mp4") { + return false + } + + val videoBytes = requestExecutor.downloadFile(document) + val mp4File = convertToMp4(videoBytes, document.media.fileName ?: "video") + + try { + requestExecutor.withUploadVideoAction(message.chat) { + requestExecutor.sendVideo(message.chat, video = mp4File.asMultipartFile()) + } + requestExecutor.reply(message, text = "Вот тебе mp4, не благодари") + } finally { + mp4File.delete() + } + + return true + } + + private fun convertToMp4(bytes: ByteArray, fileName: String): File { + val directory = createTempDirectory(UUID.randomUUID().toString()).toFile() + + bytes.toTemporaryFile(directory, fileName).use { inputFile -> + val outputFile = File(directory, inputFile.nameWithoutExtension + ".mp4") + videoConvertService.convertToMp4(inputFile, outputFile) + return outputFile + } + } +} diff --git a/src/main/kotlin/com/github/djaler/evilbot/service/VideoConvertService.kt b/src/main/kotlin/com/github/djaler/evilbot/service/VideoConvertService.kt new file mode 100644 index 00000000..952f1d00 --- /dev/null +++ b/src/main/kotlin/com/github/djaler/evilbot/service/VideoConvertService.kt @@ -0,0 +1,25 @@ +package com.github.djaler.evilbot.service + +import org.springframework.stereotype.Service +import ws.schild.jave.Encoder +import ws.schild.jave.MultimediaObject +import ws.schild.jave.encode.AudioAttributes +import ws.schild.jave.encode.EncodingAttributes +import ws.schild.jave.encode.VideoAttributes +import java.io.File + +@Service +class VideoConvertService { + fun convertToMp4(input: File, output: File) { + val audioAttributes = AudioAttributes() + val videoAttributes = VideoAttributes() + val encodingAttributes = EncodingAttributes().apply { + setAudioAttributes(audioAttributes) + setVideoAttributes(videoAttributes) + setOutputFormat("mp4") + } + + val encoder = Encoder() + encoder.encode(MultimediaObject(input), output, encodingAttributes) + } +} diff --git a/src/main/kotlin/com/github/djaler/evilbot/utils/Files.kt b/src/main/kotlin/com/github/djaler/evilbot/utils/Files.kt index 1a06ba17..1071185a 100644 --- a/src/main/kotlin/com/github/djaler/evilbot/utils/Files.kt +++ b/src/main/kotlin/com/github/djaler/evilbot/utils/Files.kt @@ -5,6 +5,7 @@ import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile import io.ktor.client.statement.* import io.ktor.utils.io.streams.* import org.springframework.core.io.ClassPathResource +import java.io.File fun ClassPathResource.asMultipartFile() = MultipartFile( filename ?: throw IllegalArgumentException("Incorrect resource provided: $this"), @@ -12,3 +13,15 @@ fun ClassPathResource.asMultipartFile() = MultipartFile( ) suspend fun HttpResponse.asMultipartFile(filename: String) = bodyAsChannel().asMultipartFile(filename) + +fun ByteArray.toTemporaryFile(parent: File, name: String): TempFile { + val file = TempFile(parent.resolve(name).path) + file.writeBytes(this) + return file +} + +class TempFile(path: String) : File(path), AutoCloseable { + override fun close() { + delete() + } +}