From 8f426927081f0787ffebb522065b64e12980ff74 Mon Sep 17 00:00:00 2001 From: Jganenokk Date: Thu, 30 Jul 2026 14:48:52 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4?= =?UTF-8?q?=D0=B0=20=D0=BF=D1=80=D0=B8=D0=BA=D0=BE=D0=BB=D0=B0=20=D1=81=20?= =?UTF-8?q?=D0=BA=D1=80=D1=83=D0=B6=D0=BA=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/debug/fake_video_note.mp4 | Bin 0 -> 4922 bytes lib/frontend/commands/command_registry.dart | 6 ++ .../commands/fake_video_message_command.dart | 67 ++++++++++++++++++ lib/frontend/commands/slash_command.dart | 4 ++ lib/frontend/screens/chats/chat_screen.dart | 1 + pubspec.yaml | 1 + 6 files changed, 79 insertions(+) create mode 100644 assets/debug/fake_video_note.mp4 create mode 100644 lib/frontend/commands/fake_video_message_command.dart diff --git a/assets/debug/fake_video_note.mp4 b/assets/debug/fake_video_note.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..9e1a713942d331876f1cf1b05a115dd5220c5881 GIT binary patch literal 4922 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 literal 0 HcmV?d00001 diff --git a/lib/frontend/commands/command_registry.dart b/lib/frontend/commands/command_registry.dart index 612b5d0..1bea90a 100644 --- a/lib/frontend/commands/command_registry.dart +++ b/lib/frontend/commands/command_registry.dart @@ -1,6 +1,7 @@ import 'anim_command.dart'; import 'crush_command.dart'; import 'epsh_files_command.dart'; +import 'fake_video_message_command.dart'; import 'info_command.dart'; import 'send_control_command.dart'; import 'slash_command.dart'; @@ -22,6 +23,11 @@ const List kSlashCommands = [ run: runCrush, hidden: true, ), + SlashCommand( + '/FakeVideoMessage', + 'кружок с подменённой длиной: [13:37 | 10000 (сек)]', + run: runFakeVideoMessage, + ), SlashCommand( '/sendControlPayload', 'CONTROL в текущий чат: [event | json]', diff --git a/lib/frontend/commands/fake_video_message_command.dart b/lib/frontend/commands/fake_video_message_command.dart new file mode 100644 index 0000000..546f65e --- /dev/null +++ b/lib/frontend/commands/fake_video_message_command.dart @@ -0,0 +1,67 @@ +import 'probe_send.dart'; +import 'slash_command.dart'; + +const String _noteAsset = 'assets/debug/fake_video_note.mp4'; +const String _usage = + 'Формат: /FakeVideoMessage 13:37 (мм:сс) или /FakeVideoMessage 10000 (секунды)'; + +int? parseFakeDurationMs(String raw) { + final input = raw.trim(); + if (input.isEmpty) return null; + + final negative = input.startsWith('-'); + final body = negative ? input.substring(1).trim() : input; + if (body.isEmpty) return null; + + int? seconds; + if (body.contains(':')) { + final parts = body.split(':'); + if (parts.length > 3) return null; + var total = 0; + for (var i = 0; i < parts.length; i++) { + final value = int.tryParse(parts[i]); + if (value == null || value < 0) return null; + if (i > 0 && value > 59) return null; + total = total * 60 + value; + } + seconds = total; + } else { + final value = int.tryParse(body); + if (value == null || value < 0) return null; + seconds = value; + } + + final ms = seconds * 1000; + return negative ? -ms : ms; +} + +String formatDurationMs(int ms) { + final sign = ms < 0 ? '-' : ''; + final totalSeconds = (ms.abs() / 1000).round(); + final hours = totalSeconds ~/ 3600; + final minutes = (totalSeconds % 3600) ~/ 60; + final seconds = totalSeconds % 60; + final mm = minutes.toString().padLeft(2, '0'); + final ss = seconds.toString().padLeft(2, '0'); + return hours > 0 ? '$sign$hours:$mm:$ss' : '$sign$minutes:$ss'; +} + +Future runFakeVideoMessage(CommandContext ctx) async { + final durationMs = parseFakeDurationMs(ctx.args); + if (durationMs == null) { + ctx.notify(_usage); + return; + } + + ctx.notify( + 'Кружок с подменой: ${formatDurationMs(durationMs)} ' + '(duration=$durationMs мс)', + ); + + try { + final file = await assetToTempFile(_noteAsset, extension: 'mp4'); + await ctx.sendVideoNote(file, durationMs); + } catch (e) { + ctx.notify('Не удалось подготовить кружок: $e'); + } +} diff --git a/lib/frontend/commands/slash_command.dart b/lib/frontend/commands/slash_command.dart index 20ab681..36af2f7 100644 --- a/lib/frontend/commands/slash_command.dart +++ b/lib/frontend/commands/slash_command.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import '../../backend/modules/messages.dart'; import '../../core/media/gallery_source.dart'; @@ -18,6 +20,7 @@ class CommandContext { final Future Function(String id, String text) updateMessage; final Future Function(List photos, String caption) sendPhotos; + final Future Function(File file, int durationMs) sendVideoNote; const CommandContext({ required this.accountId, @@ -31,6 +34,7 @@ class CommandContext { required this.postMessage, required this.updateMessage, required this.sendPhotos, + required this.sendVideoNote, }); void notifyAntiFlood() => diff --git a/lib/frontend/screens/chats/chat_screen.dart b/lib/frontend/screens/chats/chat_screen.dart index 07bc5bd..50b856e 100644 --- a/lib/frontend/screens/chats/chat_screen.dart +++ b/lib/frontend/screens/chats/chat_screen.dart @@ -3985,6 +3985,7 @@ class _ChatScreenState extends State postMessage: _postCommandMessage, updateMessage: _updateCommandMessage, sendPhotos: _sendPhotos, + sendVideoNote: _sendVideoNote, ); Future _scheduleMessage() async { diff --git a/pubspec.yaml b/pubspec.yaml index 18e0240..17411ca 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -150,6 +150,7 @@ flutter: - assets/emoji_keywords.json - assets/lottie/ - assets/wallpapers/patterns/ + - assets/debug/ fonts: - family: Inter