diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b6425650..1490e0610 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Features: - Add support for `parse_mode` parsing for story methods. - `getReply` now simply returns null if the message doesn't reply to any other message. - `getReply` now has an optional parameter that can be used to filter the returned message type. -- Added `isUser()`, `isBot()` messages to check whether the current user is a user or a bot. +- Added `isSelfUser()`, `isSelfBot()` messages to check whether the current user is a user or a bot. - Improved IDE typehinting. - CLI bots: you can now optionally specify a default download link URL (used by `getDownloadLink`) in the settings. diff --git a/README.md b/README.md index 81b6191e9..0360e7c0f 100644 --- a/README.md +++ b/README.md @@ -771,9 +771,9 @@ Want to add your own open-source project to this list? [Click here!](https://doc * Returns the session name: getSessionName * Returns the support user for the "ask a question" feature: help.getSupport * Returns users found by username substring: contacts.search - * Returns whether the current user is a bot: isBot + * Returns whether the current user is a bot: isSelfBot * Returns whether the current user is a premium user, cached: isPremium - * Returns whether the current user is a user: isUser + * Returns whether the current user is a user: isSelfUser * Reupload telegram file: uploadFromTgfile * Save a message draft associated to a chat: messages.saveDraft * Save a theme: account.saveTheme diff --git a/docs b/docs index 54835c5b7..8c9a9de03 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 54835c5b71a119041f6639d69262a81b6b7ca310 +Subproject commit 8c9a9de0318fb2e52cf802bdc5dcb83660ee4fc6 diff --git a/examples/bot.php b/examples/bot.php index 0a00123f8..6f755bbf6 100755 --- a/examples/bot.php +++ b/examples/bot.php @@ -151,7 +151,7 @@ class MyEventHandler extends SimpleEventHandler #[FilterCommand('story')] public function storyCommand(Message & FromAdmin $message): void { - if ($this->isBot()) { + if ($this->isSelfBot()) { $message->reply("Only users can post Telegram Stories!"); return; } diff --git a/examples/tgstories_dl_bot.php b/examples/tgstories_dl_bot.php new file mode 100644 index 000000000..c969ccfdc --- /dev/null +++ b/examples/tgstories_dl_bot.php @@ -0,0 +1,87 @@ +. + * + * @author Daniil Gentili + * @copyright 2016-2023 Daniil Gentili + * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 + * @link https://docs.madelineproto.xyz MadelineProto documentation + */ + +use danog\MadelineProto\API; +use danog\MadelineProto\EventHandler\Filter\FilterCommand; +use danog\MadelineProto\EventHandler\Message; +use danog\MadelineProto\EventHandler\SimpleFilter\Incoming; +use danog\MadelineProto\ParseMode; +use danog\MadelineProto\SimpleEventHandler; + +require 'vendor/autoload.php'; + +final class StoriesEventHandler extends SimpleEventHandler +{ + private const HELP = "Telegram stories downloader bot, powered by @MadelineProto!\n\nUsage:\n- /dlStories @username - Download all the stories of a username!"; + + private API $userInstance; + public function onStart(): void + { + // Login as a user + $this->userInstance = new API('stories_user.madeline'); + $this->userInstance->start(); + if (!$this->userInstance->isSelfUser()) { + throw new AssertionError("You must login as a user! Please delete the user.madeline folder to continue."); + } + } + + #[FilterCommand('start')] + public function startCmd(Incoming&Message $message): void + { + $message->reply(self::HELP, parseMode: ParseMode::MARKDOWN); + } + + /** + * Downloads all telegram stories of a user (including protected ones). + * + * The bot must be started via web for this command to work. + * + * You can also start it via CLI but you'll have to specify a download script URL in the settings: https://docs.madelineproto.xyz/docs/FILES.html#getting-a-download-link-cli-bots. + */ + #[FilterCommand('dlStories')] + public function dlStoriesCommand(Message $message): void + { + if (!$message->commandArgs) { + $message->reply("You must specify the @username or the Telegram ID of a user to download their stories!"); + return; + } + + $stories = $this->userInstance->stories->getUserStories(user_id: $message->commandArgs[0])['stories']['stories']; + // Skip deleted stories + $stories = array_filter($stories, fn (array $s): bool => $s['_'] === 'storyItem'); + // Sort by date + usort($stories, fn ($a, $b) => $a['date'] <=> $b['date']); + + $result = "Total stories: ".count($stories)."\n\n"; + foreach ($stories as $story) { + $cur = "- ID {$story['id']}, posted ".date(DATE_RFC850, $story['date']); + if (isset($story['caption'])) { + $cur .= ', "'.self::markdownEscape($story['caption']).'"'; + } + $result .= "$cur; [click here to download ยป]({$this->userInstance->getDownloadLink($story)})\n"; + } + + $message->reply($result, parseMode: ParseMode::MARKDOWN); + } +} + +$token = ''; + +StoriesEventHandler::startAndLoopBot('stories.madeline', $token); diff --git a/src/InternalDoc.php b/src/InternalDoc.php index a3eaff9fa..6df8908dd 100644 --- a/src/InternalDoc.php +++ b/src/InternalDoc.php @@ -1189,13 +1189,6 @@ abstract class InternalDoc { return \danog\MadelineProto\Tools::isArrayOrAlike($var); } - /** - * Returns whether the current user is a bot. - */ - public function isBot(): bool - { - return $this->wrapper->getAPI()->isBot(); - } /** * Check if the specified peer is a forum. * @@ -1225,6 +1218,20 @@ abstract class InternalDoc { return $this->wrapper->getAPI()->isPremium(); } + /** + * Returns whether the current user is a bot. + */ + public function isSelfBot(): bool + { + return $this->wrapper->getAPI()->isSelfBot(); + } + /** + * Returns whether the current user is a user. + */ + public function isSelfUser(): bool + { + return $this->wrapper->getAPI()->isSelfUser(); + } /** * Check whether provided bot API ID is a channel or supergroup. * @@ -1234,13 +1241,6 @@ abstract class InternalDoc { return \danog\MadelineProto\MTProto::isSupergroup($id); } - /** - * Returns whether the current user is a user. - */ - public function isUser(): bool - { - return $this->wrapper->getAPI()->isUser(); - } /** * Logger. * diff --git a/src/MTProto.php b/src/MTProto.php index e0b5c906c..5f0b4de1b 100644 --- a/src/MTProto.php +++ b/src/MTProto.php @@ -1532,14 +1532,14 @@ final class MTProto implements TLCallback, LoggerGetter /** * Returns whether the current user is a bot. */ - public function isBot(): bool + public function isSelfBot(): bool { return $this->authorization['user']['bot']; } /** * Returns whether the current user is a user. */ - public function isUser(): bool + public function isSelfUser(): bool { return !$this->authorization['user']['bot']; } diff --git a/src/Serialization.php b/src/Serialization.php index d28e2f24f..caee0c5a0 100644 --- a/src/Serialization.php +++ b/src/Serialization.php @@ -195,8 +195,9 @@ abstract class Serialization Logger::log("We don't have access to the event handler class, so we can't start it.", Logger::ERROR); Logger::log('Please start the event handler or unset it to use the IPC server.', Logger::ERROR); return $ipcSocket ?? self::tryConnect($session->getIpcPath(), $cancelIpc->getFuture()); + } elseif (\is_subclass_of($class, EventHandler::class)) { + EventHandler::cachePlugins($class); } - EventHandler::cachePlugins($class); } $tempId = Shutdown::addCallback($unlock = static function () use ($unlock): void {