How send messages.sendMultiMedia
Closed this issue · 4 comments
php: 8.2
laravel/framework": 11.22.0
danog/madelineproto: 8.3.0
Hello! I'm trying to execute the following code:
<?php
namespace App\Console\Commands;
use App\MailingStatusEnum;
use App\Models\Mailing;
use App\Models\TelegramGroup;
use App\Models\TelegramUser;
use App\Models\Topic;
use danog\MadelineProto\API;
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\ParseMode;
use danog\MadelineProto\RemoteUrl;
use Illuminate\Console\Command;
use Throwable;
class SendMailingsCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:send-mailings-command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Проверяет все рассылки в статусе new и отправляет';
/**
* Execute the console command.
*/
public function handle(): void
{
$madelineProto = new API('session.madeline');
Mailing::query()
->where('status', MailingStatusEnum::NEW)
->each(function (Mailing $mailing) use ($madelineProto) {
try {
$mailing->update(['status' => MailingStatusEnum::PROCESSING]);
foreach ($mailing->telegram_group_ids as $telegramGroupId) {
$group = TelegramGroup::query()->find($telegramGroupId);
$text = str_replace(' ', ' ', $mailing->text) . '<br /><br />';
$group
->usersWithRoles()
->whereIn('role_id', $mailing->role_ids)
->each(function (TelegramUser $telegramUser) use (&$text) {
$text .= $telegramUser->telegram_tag ? ' @'.$telegramUser->telegram_tag : " <a href='tg://user?id={$telegramUser->id}'>$telegramUser->name</a>";
});
$media = [];
$mediaFiles = $mailing->getMedia();
foreach ($mediaFiles as $index => $mediaFile) {
$filePath = $mediaFile->getPath();
$media[] = [
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => new LocalFile($filePath),
'mime_type' => mime_content_type($filePath),
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => basename($filePath)]
]
],
// 'message' => $index === 0 ? $text : '',
// 'parse_mode' => ParseMode::HTML,
];
}
$mailing->update([
'media_files' => $media
]);
$group
->topics()
->whereIn('name', $mailing->topic_ids)
->each(fn(Topic $topic) => count($media) === 0
? $madelineProto
->sendMessage(
peer: $group->telegram_id,
message: $text,
parseMode: ParseMode::HTML,
replyToMsgId: $topic->topic_id,
topMsgId: $topic->topic_id,
)
: $madelineProto
->messages
->sendMultiMedia(
peer: $group->telegram_id,
reply_to_msg_id: $topic->topic_id,
top_msg_id: $topic->topic_id,
multi_media: $media,
)
);
}
$mailing->update(['status' => MailingStatusEnum::SENDED]);
} catch (Throwable $e) {
logger("error", [$e]);
$mailing->update([
'status' => MailingStatusEnum::FAILED,
'error' => [$e],
]);
}
});
}
}
When I run it I get the error:
[2024-09-08 23:38:07] local.DEBUG: error ["[object] (danog\\MadelineProto\\TL\\Exception(code: 0): Predicate (value under _) was not set! at /home/vlad/Desktop/projects/telegram-bot-chicko/vendor/danog/madelineproto/src/TL/TL.php:601)
[stacktrace]
#0 /home/vlad/Desktop/projects/telegram-bot-chicko/vendor/danog/madelineproto/src/TL/TL.php(567): danog\\MadelineProto\\TL\\TL->serializeObject()
#1 /home/vlad/Desktop/projects/telegram-bot-chicko/vendor/danog/madelineproto/src/TL/TL.php(774): danog\\MadelineProto\\TL\\TL->serializeObject()
#2 /home/vlad/Desktop/projects/telegram-bot-chicko/vendor/danog/madelineproto/src/TL/TL.php(638): danog\\MadelineProto\\TL\\TL->serializeParams()
#3 /home/vlad/Desktop/projects/telegram-bot-chicko/vendor/danog/madelineproto/src/Connection.php(562): danog\\MadelineProto\\TL\\TL->serializeMethod()
I can’t figure out what attribute I need to pass and how to proceed? In my case, in theory, json, mp4, png, jpeg and others can be transmitted. Please tell me what to do?
*If necessary, I can send you the full error trace.
I will also add the code of my new attempt. I have taken out the file processing and now I am trying to understand more clearly what file I am dealing with when forming "multi_media"
Output logger('mediaResultArray', [$media]):
[
{
"media": {
"_": "inputMediaUploadedPhoto",
"file": {
"danog\\MadelineProto\\LocalFile": {
"file": "/home/vlad/Desktop/projects/telegram-bot-chicko/storage/app/public/2/01J79Z355SW6DQMCMATD0VFZTY.png"
}
}
},
"message": "<p>test</p><br /><br /> @eteeeeernal",
"parse_mode": {
"danog\\MadelineProto\\ParseMode": "HTML"
}
}
]
<?php
namespace App\Console\Commands;
use App\MailingStatusEnum;
use App\Models\Mailing;
use App\Models\TelegramGroup;
use App\Models\TelegramUser;
use App\Models\Topic;
use danog\MadelineProto\API;
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\ParseMode;
use danog\MadelineProto\RemoteUrl;
use Illuminate\Console\Command;
use Throwable;
class SendMailingsCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:send-mailings-command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Проверяет все рассылки в статусе new и отправляет';
/**
* Execute the console command.
*/
public function handle(): void
{
$madelineProto = new API('session.madeline');
Mailing::query()
->where('status', MailingStatusEnum::NEW)
->each(function (Mailing $mailing) use ($madelineProto) {
try {
$mailing->update(['status' => MailingStatusEnum::PROCESSING]);
foreach ($mailing->telegram_group_ids as $telegramGroupId) {
$group = TelegramGroup::query()->find($telegramGroupId);
$text = str_replace(' ', ' ', $mailing->text) . '<br /><br />';
$group
->usersWithRoles()
->whereIn('role_id', $mailing->role_ids)
->each(function (TelegramUser $telegramUser) use (&$text) {
$text .= $telegramUser->telegram_tag ? ' @'.$telegramUser->telegram_tag : " <a href='tg://user?id={$telegramUser->id}'>$telegramUser->name</a>";
});
$media = [];
$mediaFiles = $mailing->getMedia();
foreach ($mediaFiles as $index => $mediaFile) {
// $filePath = $mediaFile->getPath();
if ($file = $this->handleFile($mediaFile, $index, $text)) {
logger('file', [$file]);
$media[] = $file;
}
}
logger('mediaResultArray', [$media]);
$mailing->update([
'media_files' => $media
]);
$group
->topics()
->whereIn('name', $mailing->topic_ids)
->each(fn(Topic $topic) => count($media) === 0
? $madelineProto
->sendMessage(
peer: $group->telegram_id,
message: $text,
parseMode: ParseMode::HTML,
replyToMsgId: $topic->topic_id,
topMsgId: $topic->topic_id,
)
: $madelineProto
->messages
->sendMultiMedia(
peer: $group->telegram_id,
reply_to_msg_id: $topic->topic_id,
top_msg_id: $topic->topic_id,
multi_media: $media,
)
);
}
$mailing->update(['status' => MailingStatusEnum::SENDED]);
} catch (Throwable $e) {
logger("error", [$e]);
$mailing->update([
'status' => MailingStatusEnum::FAILED,
'error' => [$e],
]);
}
});
}
protected function handleFile($mediaFile, int $index, string $text): array|null
{
$filePath = $mediaFile->getPath();
$mimeType = mime_content_type($filePath);
// Логика для обработки различных типов медиафайлов
if (strpos($mimeType, 'image') !== false) {
// images
return [
'media' => [
'_' => 'inputMediaUploadedPhoto',
'file' => new LocalFile($filePath),
],
'message' => $index === 0 ? $text : '',
'parse_mode' => ParseMode::HTML,
];
} elseif (strpos($mimeType, 'video') !== false) {
// videos
return [
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => new LocalFile($filePath),
'mime_type' => $mimeType,
'attributes' => [
['_' => 'documentAttributeVideo', 'supports_streaming' => true]
]
],
'message' => $index === 0 ? $text : '',
'parse_mode' => ParseMode::HTML,
];
} elseif (strpos($mimeType, 'audio') !== false) {
// audios
return [
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => new LocalFile($filePath),
'mime_type' => $mimeType,
'attributes' => [
['_' => 'documentAttributeAudio', 'voice' => false]
]
],
'message' => $index === 0 ? $text : '',
'parse_mode' => ParseMode::HTML,
];
} elseif (strpos($mimeType, 'application') !== false) {
//(PDF, JSON, ZIP, ...)
return [
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => new LocalFile($filePath),
'mime_type' => $mimeType,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => basename($filePath)]
]
],
'message' => $index === 0 ? $text : '',
'parse_mode' => ParseMode::HTML,
];
} elseif (strpos($mimeType, 'text') !== false) {
// (HTML, plain text, ...)
return [
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => new LocalFile($filePath),
'mime_type' => $mimeType,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => basename($filePath)]
]
],
'message' => $index === 0 ? $text : '',
'parse_mode' => ParseMode::HTML,
];
}
return null;
}
}
i solved my problem.
Solve:
return [
**'_' => 'inputSingleMedia',**
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => new LocalFile($filePath),
'mime_type' => $mimeType,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => basename($filePath)]
]
],
'message' => $index === 0 ? $text : '',
'parse_mode' => ParseMode::HTML,
];
Added '_' => 'inputSingleMedia', in my media array
I would like to add to my answer. After solving the problem, I still had difficulty loading video+any other file. My salvation was 'force_file' => true. In this case, all media are compressed, but no longer conflict when loading, because otherwise tg does not allow loading a video with another file in one message.
New working structure:
return [
'_' => 'inputSingleMedia',
'media' => [
'_' => 'inputMediaUploadedDocument',
'force_file' => true,
'file' => new LocalFile($filePath),
'mime_type' => $mimeType,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => basename($filePath)]
]
],
'message' => $index === $count - 1 ? $text : '',
'parse_mode' => ParseMode::HTML,
];
I will also be happy to share my fully working script.
*To work with media inside the project, I use spatie/laravel-medialibrary package
working code:
<?php
namespace App\Console\Commands;
use App\MailingStatusEnum;
use App\Models\Mailing;
use App\Models\TelegramGroup;
use App\Models\TelegramUser;
use App\Models\Topic;
use danog\MadelineProto\API;
use danog\MadelineProto\LocalFile;
use danog\MadelineProto\ParseMode;
use Illuminate\Console\Command;
use Throwable;
class SendMailingsCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:send-mailings-command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Проверяет все рассылки в статусе new и отправляет';
/**
* Execute the console command.
*/
public function handle(): void
{
if (Mailing::query()->where('status', MailingStatusEnum::PROCESSING)->count() > 0) {
return; // Если что-то уже участвует в рассылке, то мы пропускаем и ждём пока освободится пул отправок
}
$madelineProto = new API('session.madeline');
$mailing = Mailing::query()
->where('status', MailingStatusEnum::NEW)
->first();
if (!$mailing) {
return; // Если новых рассылок нет, то просто завершаем скрипт
}
try {
$mailing->update(['status' => MailingStatusEnum::PROCESSING]);
foreach ($mailing->telegram_group_ids as $telegramGroupId) {
$group = TelegramGroup::query()->find($telegramGroupId);
$text = str_replace(' ', ' ', $mailing->text) . '<br /><br />';
$group
->usersWithRoles()
->whereIn('role_id', $mailing->role_ids)
->each(function (TelegramUser $telegramUser) use (&$text) {
$text .= $telegramUser->telegram_tag ? ' @'.$telegramUser->telegram_tag : " <a href='tg://user?id={$telegramUser->id}'>$telegramUser->name</a>";
});
$media = [];
$mediaFiles = $mailing->getMedia();
foreach ($mediaFiles as $index => $mediaFile) {
if ($file = $this->handleFile($mediaFile, $index, $text, $mediaFiles->count())) {
logger('file', [$file]);
$media[] = $file;
}
}
logger('mediaResultArray', [$media]);
$mailing->update([
'media_files' => $media
]);
$group
->topics()
->whereIn('name', $mailing->topic_ids)
->each(fn(Topic $topic) => count($media) === 0
? $madelineProto
->sendMessage(
peer: $group->telegram_id,
message: $text,
parseMode: ParseMode::HTML,
replyToMsgId: $topic->topic_id,
topMsgId: $topic->topic_id,
)
: $madelineProto
->messages
->sendMultiMedia(
peer: $group->telegram_id,
reply_to_msg_id: $topic->topic_id,
top_msg_id: $topic->topic_id,
multi_media: $media,
)
);
}
$mailing->update(['status' => MailingStatusEnum::SENDED]);
} catch (Throwable $e) {
logger("error", [$e]);
$mailing->update([
'status' => MailingStatusEnum::FAILED,
'error' => [$e],
]);
}
}
protected function handleFile($mediaFile, int $index, string $text, $count): array|null
{
$filePath = $mediaFile->getPath();
$mimeType = mime_content_type($filePath);
return [
'_' => 'inputSingleMedia',
'media' => [
'_' => 'inputMediaUploadedDocument',
'force_file' => true,
'file' => new LocalFile($filePath),
'mime_type' => $mimeType,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => basename($filePath)]
]
],
'message' => $index === $count - 1 ? $text : '',
'parse_mode' => ParseMode::HTML,
];
}
}
+1