1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-30 05:58:58 +01:00

Improve getInfo/getType, add wrapper methods

This commit is contained in:
Daniil Gentili 2023-07-04 19:48:23 +02:00
parent 6a8fcda99e
commit a157f277c1
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
22 changed files with 396 additions and 56 deletions

View File

@ -7,7 +7,7 @@ $config = new class extends Amp\CodeStyle\Config {
'void_return' => true,
'array_indentation' => true,
'ternary_to_null_coalescing' => true,
'assign_null_coalescing_to_coalesce_equal' => true
'assign_null_coalescing_to_coalesce_equal' => true,
]);
}
};

View File

@ -528,7 +528,7 @@ Want to add your own open-source project to this list? [Click here!](https://doc
* <a href="https://docs.madelineproto.xyz/API_docs/methods/payments.getSavedInfo.html" name="payments.getSavedInfo">Get saved payment information: payments.getSavedInfo</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.getScheduledHistory.html" name="messages.getScheduledHistory">Get scheduled messages: messages.getScheduledHistory</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/messages.getScheduledMessages.html" name="messages.getScheduledMessages">Get scheduled messages: messages.getScheduledMessages</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#secretchatstatus-int-chat-int-one-of-mtproto-secret_empty-mtproto-secret_requested-mtproto-secret_ready" name="secretChatStatus">Get secret chat status: secretChatStatus</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#secretchatstatus-int-chat-int-one-of-danog-madelineproto-api-secret_empty-danog-madelineproto-api-secret_requested-danog-madelineproto-api-secret_ready" name="secretChatStatus">Get secret chat status: secretChatStatus</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#getsecretchat-array-int-chat-array" name="getSecretChat">Get secret chat: getSecretChat</a>
* <a href="https://docs.madelineproto.xyz/PHP/danog/MadelineProto/API.html#random-int-length-string" name="random">Get secure random string of specified length: random</a>
* <a href="https://docs.madelineproto.xyz/API_docs/methods/account.getContentSettings.html" name="account.getContentSettings">Get sensitive content settings: account.getContentSettings</a>

View File

@ -2,10 +2,13 @@
namespace danog\MadelineProto\EventHandler;
use danog\MadelineProto\Ipc\IpcCapable;
use danog\MadelineProto\MTProto;
/**
* Represents a generic media.
*/
abstract class Media
abstract class Media extends IpcCapable
{
/** Media filesize */
public readonly int $size;
@ -13,6 +16,9 @@ abstract class Media
/** Media file name */
public readonly string $fileName;
/** Media file extension */
public readonly string $fileExt;
/** Media creation date */
public readonly bool $creationDate;
@ -22,27 +28,35 @@ abstract class Media
/** Time-to-live of media */
public readonly ?int $ttl;
/** @var list<Media> Thumbnails */
/** @var list<array> Thumbnails */
public readonly array $thumbs;
/** @var list<Media> Video thumbnails */
/** @var list<array> Video thumbnails */
public readonly array $videoThumbs;
/** Whether the media should be hidden behind a spoiler */
public readonly bool $spoiler;
/** If true, the current media has attached mask stickers. */
public readonly bool $hasStickers;
/** Media location */
private readonly array $location;
/** Media ID */
private readonly int $documentId;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
) {
parent::__construct($API);
[
'name' => $name,
'ext' => $this->fileExt,
'mime' => $this->mimeType,
'size' => $this->size,
'InputFileLocation' => $this->location
] = $API->getDownloadInfo($rawMedia);
$this->fileName = "$name.".$this->fileExt;
/** Media access hash */
private readonly int $documentAccessHash;
/** Media file reference */
private readonly int $fileReference;
/** DC ID */
private readonly int $dcId;
$this->creationDate = $rawMedia['date'];
$this->ttl = $rawMedia['ttl_seconds'] ?? null;
$this->spoiler = $rawMedia['spoiler'] ?? false;
}
}

View File

@ -9,5 +9,17 @@ use danog\MadelineProto\EventHandler\Media;
*/
abstract class AbstractAudio extends Media
{
/** Audio duration in seconds */
public readonly int $duration;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $audioAttribute
) {
{
parent::__construct($API, $rawMedia);
$this->duration = $audioAttribute['duration'];
}
}

View File

@ -14,4 +14,16 @@ abstract class AbstractSticker extends Media
/** Associated stickerset */
public readonly array $stickerset;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $stickerAttribute
) {
{
parent::__construct($API, $rawMedia);
$this->emoji = $stickerAttribute['alt'];
$this->stickerset = $stickerAttribute['stickerset'];
}
}

View File

@ -17,4 +17,18 @@ abstract class AbstractVideo extends Media
public readonly int $width;
/** Video height */
public readonly int $height;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $attribute
) {
{
parent::__construct($API, $rawMedia);
$this->duration = $attribute['duration'];
$this->supportsStreaming = $attribute['supports_streaming'];
$this->width = $attribute['w'];
$this->height = $attribute['h'];
}
}

View File

@ -11,10 +11,16 @@ final class Audio extends AbstractAudio
public readonly ?string $title;
/** Performer */
public readonly ?string $performer;
/**
* 100 values from 0 to 31, representing a waveform.
*
* @var list<int>|null
*/
public readonly ?array $waveform;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $audioAttribute
) {
{
parent::__construct($API, $rawMedia);
$this->title = $audioAttribute['title'] ?? null;
$this->performer = $audioAttribute['performer'] ?? null;
}
}

View File

@ -11,4 +11,16 @@ final class CustomEmoji extends AbstractSticker
public readonly bool $free;
/** Whether the color of this TGS custom emoji should be changed to the text color when used in messages, the accent color if used as emoji status, white on chat photos, or another appropriate color based on context. */
public readonly bool $textColor;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $stickerAttribute
) {
{
parent::__construct($API, $rawMedia, $stickerAttribute);
$this->free = $stickerAttribute['free'];
$this->textColor = $stickerAttribute['text_color'];
}
}

View File

@ -0,0 +1,20 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Media;
use danog\MadelineProto\EventHandler\Media;
/**
* Represents a document.
*/
final class Document extends Media
{
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia
) {
{
parent::__construct($API, $rawMedia);
}
}

View File

@ -0,0 +1,37 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Media;
use danog\MadelineProto\EventHandler\Media;
/**
* Represents a photo uploaded as a document.
*/
final class DocumentPhoto extends Media
{
/** If true; the current media has attached mask stickers. */
public readonly bool $hasStickers;
public readonly int $width;
public readonly int $height;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $attribute
) {
{
parent::__construct($API, $rawMedia);
$this->width = $attribute['w'];
$this->height = $attribute['h'];
$hasStickers = false;
foreach ($rawMedia['attributes'] as ['_' => $t]) {
if ($t === 'documentAttributeHasStickers') {
$hasStickers = true;
break;
}
}
$this->hasStickers = $hasStickers;
}
}

View File

@ -7,4 +7,24 @@ namespace danog\MadelineProto\EventHandler\Media;
*/
final class Gif extends AbstractVideo
{
/** If true; the current media has attached mask stickers. */
public readonly bool $hasStickers;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $attribute
) {
{
parent::__construct($API, $rawMedia, $attribute);
$hasStickers = false;
foreach ($rawMedia['attributes'] as ['_' => $t]) {
if ($t === 'documentAttributeHasStickers') {
$hasStickers = true;
break;
}
}
$this->hasStickers = $hasStickers;
}
}

View File

@ -10,7 +10,7 @@ final class MaskSticker extends AbstractSticker
/**
* Part of the face, relative to which the mask should be placed.
*/
public readonly MaskPosition $n;
public readonly MaskPosition $position;
/**
* Shift by X-axis measured in widths of the mask scaled to the face size, from left to right.
*
@ -29,4 +29,24 @@ final class MaskSticker extends AbstractSticker
* For example, 2.0 means a doubled size.
*/
public readonly float $zoom;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $stickerAttribute
) {
{
parent::__construct($API, $rawMedia, $stickerAttribute);
$coords = $stickerAttribute['mask_coords'];
$this->position = match ($coords['n']) {
0 => MaskPosition::Forehead,
1 => MaskPosition::Eyes,
2 => MaskPosition::Mouth,
3 => MaskPosition::Chin
};
$this->x = $coords['x'];
$this->y = $coords['y'];
$this->zoom = $coords['zoom'];
}
}

View File

@ -9,4 +9,23 @@ use danog\MadelineProto\EventHandler\Media;
*/
final class Photo extends Media
{
/** If true; the current media has attached mask stickers. */
public readonly bool $hasStickers;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia
) {
{
parent::__construct($API, $rawMedia);
$hasStickers = false;
foreach ($rawMedia['attributes'] as ['_' => $t]) {
if ($t === 'documentAttributeHasStickers') {
$hasStickers = true;
break;
}
}
$this->hasStickers = $hasStickers;
}
}

View File

@ -7,4 +7,17 @@ namespace danog\MadelineProto\EventHandler\Media;
*/
final class Sticker extends AbstractSticker
{
/** Whether this is a premium sticker and a premium sticker animation must be played. */
public readonly bool $premiumSticker;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $stickerAttribute
) {
{
parent::__construct($API, $rawMedia, $stickerAttribute);
$this->premiumSticker = !$rawMedia['nopremium'];
}
}

View File

@ -7,4 +7,24 @@ namespace danog\MadelineProto\EventHandler\Media;
*/
final class Video extends AbstractVideo
{
/** If true; the current media has attached mask stickers. */
public readonly bool $hasStickers;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $attribute
) {
{
parent::__construct($API, $rawMedia, $attribute);
$hasStickers = false;
foreach ($rawMedia['attributes'] as ['_' => $t]) {
if ($t === 'documentAttributeHasStickers') {
$hasStickers = true;
break;
}
}
$this->hasStickers = $hasStickers;
}
}

View File

@ -0,0 +1,27 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Media;
/**
* Represents a voice message.
*/
final class Voice extends AbstractAudio
{
/**
* 100 values from 0 to 31, representing a waveform.
*
* @var list<int>|null
*/
//public readonly ?array $waveform;
/** @internal */
public function __construct(
MTProto $API,
array $rawMedia,
array $audioAttribute
) {
{
parent::__construct($API, $rawMedia, $audioAttribute);
//$this->waveform = $audioAttribute['waveform'];
}
}

View File

@ -32,6 +32,9 @@ abstract class Message extends Update
/** ID of the message thread where the message was sent */
public readonly ?int $threadId;
/** Attached media */
public readonly ?Media $media;
/** Whether this is a reply to a scheduled message */
public readonly bool $replyToScheduled;
/** Whether we were mentioned in this message */
@ -65,7 +68,7 @@ abstract class Message extends Update
// Todo media, albums, reactions, replies
/** @internal */
protected function __construct(
public function __construct(
MTProto $API,
array $rawMessage,
/** Whether the message is outgoing */

View File

@ -3,34 +3,12 @@
namespace danog\MadelineProto\EventHandler;
use danog\MadelineProto\Ipc\Client;
use danog\MadelineProto\Ipc\IpcCapable;
use danog\MadelineProto\MTProto;
/**
* Represents a generic update.
*/
abstract class Update
abstract class Update extends IpcCapable
{
private readonly string $session;
protected MTProto|Client|null $API;
/** @internal */
protected function __construct(
MTProto $API,
) {
$this->API = $API;
$this->session = $API->wrapper->getSession()->getSessionDirectoryPath();
}
/** @internal */
public function __sleep()
{
$vars = \get_object_vars($this);
unset($vars['API']);
return \array_keys($vars);
}
/** @internal */
public function __wakeup(): void
{
$this->API = Client::giveInstanceBySession($this->session);
}
}

36
src/Ipc/IpcCapable.php Normal file
View File

@ -0,0 +1,36 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\Ipc;
use danog\MadelineProto\Ipc\Client;
use danog\MadelineProto\MTProto;
/**
* Represents an IPC-capable object.
*/
abstract class IpcCapable
{
private readonly string $session;
protected MTProto|Client|null $API;
/** @internal */
protected function __construct(
MTProto $API,
) {
$this->API = $API;
$this->session = $API->wrapper->getSession()->getSessionDirectoryPath();
}
/** @internal */
public function __sleep()
{
$vars = \get_object_vars($this);
unset($vars['API']);
return \array_keys($vars);
}
/** @internal */
public function __wakeup(): void
{
$this->API = Client::giveInstanceBySession($this->session);
}
}

View File

@ -24,6 +24,17 @@ use Amp\DeferredFuture;
use Amp\File\Driver\BlockingFile;
use Amp\Future;
use Amp\Http\Client\Request;
use danog\MadelineProto\EventHandler\Media\Audio;
use danog\MadelineProto\EventHandler\Media\CustomEmoji;
use danog\MadelineProto\EventHandler\Media\Document;
use danog\MadelineProto\EventHandler\Media\DocumentPhoto;
use danog\MadelineProto\EventHandler\Media\Gif;
use danog\MadelineProto\EventHandler\Media\MaskSticker;
use danog\MadelineProto\EventHandler\Media\Photo;
use danog\MadelineProto\EventHandler\Media\RoundVideo;
use danog\MadelineProto\EventHandler\Media\Sticker;
use danog\MadelineProto\EventHandler\Media\Video;
use danog\MadelineProto\EventHandler\Media\Voice;
use danog\MadelineProto\Exception;
use danog\MadelineProto\FileCallbackInterface;
use danog\MadelineProto\Logger;
@ -36,6 +47,7 @@ use danog\MadelineProto\Tools;
use Generator;
use Revolt\EventLoop;
use Throwable;
use Webmozart\Assert\Assert;
use const LOCK_EX;
use function Amp\async;
@ -529,6 +541,55 @@ trait Files
$info['file_type'] = $method;
return $info;
}
/**
* Wrap a media constructor into an abstract Media object.
*/
public function wrapMedia(array $media): Media
{
if ($media['_'] === 'messageMediaPhoto'){
return new Photo($this, $media);
}
Assert::eq($media['_'], 'messageMediaDocument');
$has_video = null;
$has_animated = false;
foreach ($media['attributes'] as $attr) {
$t = $attr['_'];
if ($t === 'documentAttributeImageSize') {
return new DocumentPhoto($this, $media, $attr);
}
if ($t === 'documentAttributeAnimated') {
$has_animated = true;
continue;
}
if ($t === 'documentAttributeSticker') {
return $attr['mask']
? new MaskSticker($this, $media, $attr)
: new Sticker($this, $media, $attr);
}
if ($t === 'documentAttributeVideo') {
$has_video = $attr;
continue;
}
if ($t === 'documentAttributeAudio') {
return $attr['voice']
? new Voice($this, $media, $attr)
: new Audio($this, $media, $attr);
}
if ($t === 'documentAttributeCustomEmoji') {
return new CustomEmoji($this, $media, $attr);
}
}
if ($has_animated) {
Assert::notNull($has_video);
return new Gif($this, $media, $has_video);
}
if ($has_video) {
return $attr['round_message']
? new RoundVideo($this, $media, $has_video)
: new Video($this, $media, $has_video);
}
return new Document($this, $media);
}
/**
* Get download info of file
* Returns an array with the following structure:.
@ -539,6 +600,14 @@ trait Files
* `$info['size']` - The file size
*
* @param mixed $messageMedia File ID
*
* @return array{
* ext: string,
* name: string,
* mime: string,
* size: int,
* InputFileLocation: array
* }
*/
public function getDownloadInfo(mixed $messageMedia): array
{
@ -637,10 +706,8 @@ trait Files
return $this->getDownloadInfo($messageMedia['document']);
// Photos
case 'photo':
$messageMedia = ['_' => 'messageMediaPhoto', 'photo' => $messageMedia, 'ttl_seconds' => 0];
case 'messageMediaPhoto':
if ($messageMedia['_'] == 'photo') {
$messageMedia = ['_' => 'messageMediaPhoto', 'photo' => $messageMedia, 'ttl_seconds' => 0];
}
$res['MessageMedia'] = $messageMedia;
$messageMedia = $messageMedia['photo'];
$size = Tools::maxSize($messageMedia['sizes']);

View File

@ -565,7 +565,7 @@ trait PeerHandler
*/
public function getType(mixed $id): string
{
return $this->getInfo($id)['type'];
return $this->getInfo($id, API::INFO_TYPE_TYPE);
}
/**
@ -588,7 +588,7 @@ trait PeerHandler
* InputUser?: array{_: string, user_id?: int, access_hash?: int, min?: bool},
* InputChannel?: array{_: string, channel_id: int, access_hash: int, min: bool},
* type: string
* } : ($type is \danog\MadelineProto\API::INFO_TYPE_ID ? int : array{_: string, user_id?: int, access_hash?: int, min?: bool, chat_id?: int, channel_id?: int}|array{_: string, user_id?: int, access_hash?: int, min?: bool}|array{_: string, channel_id: int, access_hash: int, min: bool}))
* } : ($type is API::INFO_TYPE_TYPE ? string : ($type is \danog\MadelineProto\API::INFO_TYPE_ID ? int : array{_: string, user_id?: int, access_hash?: int, min?: bool, chat_id?: int, channel_id?: int}|array{_: string, user_id?: int, access_hash?: int, min?: bool}|array{_: string, channel_id: int, access_hash: int, min: bool})))
*/
public function getInfo(mixed $id, int $type = \danog\MadelineProto\API::INFO_TYPE_ALL): array|int
{
@ -754,6 +754,17 @@ trait PeerHandler
return -$constructor['id'];
}
}
if ($type === \danog\MadelineProto\API::INFO_TYPE_TYPE) {
if ($constructor['_'] === 'user') {
return $constructor['bot'] ?? false ? 'bot' : 'user';
}
if ($constructor['_'] === 'channel') {
return $constructor['megagroup'] ?? false ? 'supergroup' : 'channel';
}
if ($constructor['_'] === 'chat' || $constructor['_'] === 'chatForbidden') {
return 'chat';
}
}
if ($type === \danog\MadelineProto\API::INFO_TYPE_USERNAMES) {
return $this->getUsernames($constructor);
}

View File

@ -26,6 +26,7 @@ use Amp\Http\Client\Request;
use Amp\Http\Client\Response;
use Amp\TimeoutCancellation;
use Amp\TimeoutException;
use danog\MadelineProto\EventHandler\Media;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Message\IncomingChannelMessage;
use danog\MadelineProto\EventHandler\Message\IncomingGroupMessage;
@ -309,7 +310,6 @@ trait UpdateHandler
}
/**
* Wrap an Update constructor into an abstract Update object.
*
*/
public function wrapUpdate(array $update): ?Update
{
@ -320,7 +320,6 @@ trait UpdateHandler
}
/**
* Wrap a Message constructor into an abstract Message object.
*
*/
public function wrapMessage(array $message): ?Message
{