Skip to content

Commit

Permalink
Add sendDocumentPhoto
Browse files Browse the repository at this point in the history
  • Loading branch information
danog committed Apr 19, 2024
1 parent 0d6d7fb commit 4c9820f
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 2 deletions.
7 changes: 7 additions & 0 deletions examples/secret_bot.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ public function handle(Incoming&SecretMessage $update): void
caption: 'This file was uploaded using MadelineProto',
);

// Photo as document, secret chat
$this->sendDocumentPhoto(
peer: $update->chatId,
file: new LocalFile('tests/faust.jpg'),
caption: 'This file was uploaded using MadelineProto',
);

// GIF, secret chat
$this->sendGif(
peer: $update->chatId,
Expand Down
28 changes: 28 additions & 0 deletions src/InternalDoc.php
Original file line number Diff line number Diff line change
Expand Up @@ -1714,6 +1714,34 @@ final public function sendDocument(string|int $peer, \danog\MadelineProto\EventH
{
return $this->wrapper->getAPI()->sendDocument($peer, $file, $thumb, $caption, $parseMode, $callback, $fileName, $mimeType, $ttl, $spoiler, $replyToMsgId, $topMsgId, $replyMarkup, $sendAs, $scheduleDate, $silent, $noForwards, $background, $clearDraft, $updateStickersetsOrder, $forceResend, $cancellation);
}
/**
* Sends a photo.
*
* Please use named arguments to call this method.
*
* @param integer|string $peer Destination peer or username.
* @param Message|Media|LocalFile|RemoteUrl|BotApiFileId|ReadableStream $file File to upload: can be a message to reuse media present in a message.
* @param string $caption Caption of document
* @param ?callable(float, float, int) $callback Upload callback (percent, speed in mpbs, time elapsed)
* @param ?string $fileName Optional file name, if absent will be extracted from the passed $file.
* @param ParseMode $parseMode Text parse mode for the caption
* @param integer|null $replyToMsgId ID of message to reply to.
* @param integer|null $topMsgId ID of thread where to send the message.
* @param array|null $replyMarkup Keyboard information.
* @param integer|null $sendAs Peer to send the message as.
* @param integer|null $scheduleDate Schedule date.
* @param boolean $silent Whether to send the message silently, without triggering notifications.
* @param boolean $background Send this message as background message
* @param boolean $clearDraft Clears the draft field
* @param boolean $updateStickersetsOrder Whether to move used stickersets to top
* @param boolean $forceResend Whether to forcefully resend the file, even if its type and name are the same.
* @param Cancellation $cancellation Cancellation.
*
*/
final public function sendDocumentPhoto(string|int $peer, \danog\MadelineProto\EventHandler\Message|\danog\MadelineProto\EventHandler\Media|\danog\MadelineProto\LocalFile|\danog\MadelineProto\RemoteUrl|\danog\MadelineProto\BotApiFileId|\Amp\ByteStream\ReadableStream $file, string $caption = '', \danog\MadelineProto\ParseMode $parseMode = \danog\MadelineProto\ParseMode::TEXT, ?callable $callback = null, ?string $fileName = null, ?int $ttl = null, bool $spoiler = false, ?int $replyToMsgId = null, ?int $topMsgId = null, ?array $replyMarkup = null, string|int|null $sendAs = null, ?int $scheduleDate = null, bool $silent = false, bool $noForwards = false, bool $background = false, bool $clearDraft = false, bool $updateStickersetsOrder = false, bool $forceResend = false, ?\Amp\Cancellation $cancellation = null): \danog\MadelineProto\EventHandler\Message
{
return $this->wrapper->getAPI()->sendDocumentPhoto($peer, $file, $caption, $parseMode, $callback, $fileName, $ttl, $spoiler, $replyToMsgId, $topMsgId, $replyMarkup, $sendAs, $scheduleDate, $silent, $noForwards, $background, $clearDraft, $updateStickersetsOrder, $forceResend, $cancellation);
}
/**
* Sends a gif.
*
Expand Down
88 changes: 86 additions & 2 deletions src/MTProtoTools/FilesAbstraction.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use danog\MadelineProto\EventHandler\Media\AbstractVideo;
use danog\MadelineProto\EventHandler\Media\Audio;
use danog\MadelineProto\EventHandler\Media\Document;
use danog\MadelineProto\EventHandler\Media\DocumentPhoto;
use danog\MadelineProto\EventHandler\Media\Gif;
use danog\MadelineProto\EventHandler\Media\Photo;
use danog\MadelineProto\EventHandler\Media\RoundVideo;
Expand Down Expand Up @@ -244,6 +245,79 @@ public function sendPhoto(
cancellation: $cancellation
);
}
/**
* Sends a photo.
*
* Please use named arguments to call this method.
*
* @param integer|string $peer Destination peer or username.
* @param Message|Media|LocalFile|RemoteUrl|BotApiFileId|ReadableStream $file File to upload: can be a message to reuse media present in a message.
* @param string $caption Caption of document
* @param ?callable(float, float, int) $callback Upload callback (percent, speed in mpbs, time elapsed)
* @param ?string $fileName Optional file name, if absent will be extracted from the passed $file.
* @param ParseMode $parseMode Text parse mode for the caption
* @param integer|null $replyToMsgId ID of message to reply to.
* @param integer|null $topMsgId ID of thread where to send the message.
* @param array|null $replyMarkup Keyboard information.
* @param integer|null $sendAs Peer to send the message as.
* @param integer|null $scheduleDate Schedule date.
* @param boolean $silent Whether to send the message silently, without triggering notifications.
* @param boolean $background Send this message as background message
* @param boolean $clearDraft Clears the draft field
* @param boolean $updateStickersetsOrder Whether to move used stickersets to top
* @param boolean $forceResend Whether to forcefully resend the file, even if its type and name are the same.
* @param Cancellation $cancellation Cancellation.
*
*/
public function sendDocumentPhoto(
int|string $peer,
Message|Media|LocalFile|RemoteUrl|BotApiFileId|ReadableStream $file,
string $caption = '',
ParseMode $parseMode = ParseMode::TEXT,
?callable $callback = null,
?string $fileName = null,
?int $ttl = null,
bool $spoiler = false,
?int $replyToMsgId = null,
?int $topMsgId = null,
?array $replyMarkup = null,
int|string|null $sendAs = null,
?int $scheduleDate = null,
bool $silent = false,
bool $noForwards = false,
bool $background = false,
bool $clearDraft = false,
bool $updateStickersetsOrder = false,
bool $forceResend = false,
?Cancellation $cancellation = null,
): Message {
return $this->sendMedia(
type: DocumentPhoto::class,
mimeType: 'image/jpeg',
thumb: null,
attributesOrig: [],
peer: $peer,
file: $file,
caption: $caption,
parseMode: $parseMode,
callback: $callback,
fileName: $fileName,
ttl: $ttl,
spoiler: $spoiler,
silent: $silent,
background: $background,
clearDraft: $clearDraft,
noForwards: $noForwards,
updateStickersetsOrder: $updateStickersetsOrder,
replyToMsgId: $replyToMsgId,
topMsgId: $topMsgId,
replyMarkup: $replyMarkup,
scheduleDate: $scheduleDate,
sendAs: $sendAs,
forceResend: $forceResend,
cancellation: $cancellation
);
}
/**
* Sends a sticker.
*
Expand Down Expand Up @@ -826,7 +900,7 @@ public function sendMedia(
$width = 0;
$height = 0;

if ($type === Photo::class || $type === Sticker::class) {
if ($type === Photo::class || $type === DocumentPhoto::class || $type === Sticker::class) {
if (!\extension_loaded('gd')) {
throw Exception::extension('gd');
}
Expand All @@ -835,7 +909,7 @@ public function sendMedia(
$width = imagesx($img);
$height = imagesy($img);
$file = new ReadableBuffer($file);
if ($type === Photo::class) {
if ($type === Photo::class || $type === DocumentPhoto::class) {
if ($width > $height) {
$thumb_width = 90;
$thumb_height = (int) (90*$height/$width);
Expand All @@ -857,6 +931,10 @@ public function sendMedia(
$thumb = stream_get_contents($stream);
fclose($stream);
unset($stream);

if ($type === DocumentPhoto::class) {
$attributes []= ['_' => 'documentAttributeImageSize', 'w' => $width, 'h' => $height];
}
} else {
$attributes []= ['_' => 'documentAttributeImageSize', 'w' => $width, 'h' => $height];
}
Expand Down Expand Up @@ -946,6 +1024,12 @@ public function sendMedia(
$mimeType = $this->extractMime(false, $file, $fileName, $callback, $cancellation);
}

if ($type === DocumentPhoto::class) {
$attributes []= [
'_' => 'documentAttributeImageSize',
];
}

$method = 'messages.sendMedia';
$media = match ($type) {
Photo::class => [
Expand Down
91 changes: 91 additions & 0 deletions src/StreamDuplicator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php declare(strict_types=1);

namespace danog\MadelineProto;

/**
* Stream duplicator module.
*
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <[email protected]>
* @copyright 2016-2023 Daniil Gentili <[email protected]>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/

namespace danog\MadelineProto;

use Amp\ByteStream\ReadableStream;
use Amp\ByteStream\ReadableStreamIteratorAggregate;
use Amp\ByteStream\WritableStream;
use Amp\Cancellation;
use Closure;
use IteratorAggregate;

use function Amp\async;

/**
* Stream duplicator.
*
* The secondary output stream is written to only when the StreamDuplicator is read.
*
* Thus, to fully duplicate a stream, both copies must be fully read until the end.
*
* @internal
*/
final class StreamDuplicator implements ReadableStream, IteratorAggregate
{
use ReadableStreamIteratorAggregate;
/** @var list<WritableStream> */
private array $outputs;
/**
* @param ReadableStream $input Input stream
* @param WritableStream ...$outputs Secondary output streams, only written to when the primary stream (this one) is read.
*/
public function __construct(
private readonly ReadableStream $input,
WritableStream ...$outputs,
) {
$this->outputs = $outputs;
}
public function read(?Cancellation $cancellation = null): ?string
{
$res = $this->input->read($cancellation);
if ($res === null) {
foreach ($this->outputs as $s) {
$s->close();
}
} else {
foreach ($this->outputs as $s) {
if (!$s->isClosed()) {
async($s->write(...), $res)->ignore();
}
}
}
return $res;
}
public function isReadable(): bool
{
return $this->input->isReadable();
}
public function close(): void
{
$this->input->close();
foreach ($this->outputs as $s) {
$s->close();
}
}
public function isClosed(): bool
{
return $this->input->isClosed();
}
public function onClose(Closure $onClose): void
{
$this->input->onClose($onClose);
}
}

0 comments on commit 4c9820f

Please sign in to comment.