From 955b9fa42cc18f76fb8aba6dfed764faf3c3c47e Mon Sep 17 00:00:00 2001 From: Sempai-07 Date: Sat, 11 Apr 2026 23:02:10 +0300 Subject: [PATCH 01/20] Fix(LanguageCode): user.language is not compatible with ISO 639-1 --- src/client/interfaces/Message.ts | 2 +- src/structures/misc/User.js | 2 +- typings/index.d.ts | 2 +- typings/telegram/Message.d.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/interfaces/Message.ts b/src/client/interfaces/Message.ts index e3ee25c..ddba1c6 100644 --- a/src/client/interfaces/Message.ts +++ b/src/client/interfaces/Message.ts @@ -13,7 +13,7 @@ export interface User { /** User's or bot's username */ username?: string; /** IETF language tag of the user's language */ - language_code?: LanguageCode; + language_code?: string; /** True, if this user is a Telegram Premium user */ is_premium?: true; /** True, if this user added the bot to the attachment menu */ diff --git a/src/structures/misc/User.js b/src/structures/misc/User.js index 3afa992..c6b9c48 100644 --- a/src/structures/misc/User.js +++ b/src/structures/misc/User.js @@ -55,7 +55,7 @@ class User extends Base { if ("language_code" in data) { /** * IETF language tag of the user's language - * @type {LanguageCode | undefined} + * @type {string | undefined} */ this.language = data.language_code; } diff --git a/typings/index.d.ts b/typings/index.d.ts index e7707ed..f2b5135 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -544,7 +544,7 @@ export declare class User extends Base { /** * IETF language tag of the user's language */ - language?: LanguageCode; + language?: string; /** * True, if this user is a Telegram Premium user */ diff --git a/typings/telegram/Message.d.ts b/typings/telegram/Message.d.ts index e3ee25c..ddba1c6 100644 --- a/typings/telegram/Message.d.ts +++ b/typings/telegram/Message.d.ts @@ -13,7 +13,7 @@ export interface User { /** User's or bot's username */ username?: string; /** IETF language tag of the user's language */ - language_code?: LanguageCode; + language_code?: string; /** True, if this user is a Telegram Premium user */ is_premium?: true; /** True, if this user added the bot to the attachment menu */ From 371f2ee0ea5fbabae9de89cb57ddf67085802cfc Mon Sep 17 00:00:00 2001 From: Sempai-07 Date: Sat, 11 Apr 2026 23:03:20 +0300 Subject: [PATCH 02/20] Bump @telegram.ts/types version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 659e48b..6218bd1 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ }, "homepage": "https://docs-telegramsjs.vercel.app/", "devDependencies": { - "@telegram.ts/types": "^1.25.1", + "@telegram.ts/types": "^1.26.0", "@types/node": "^18.19.130", "@types/node-fetch": "^2.6.11", "@types/safe-compare": "^1.1.2", From aa97e171e52dc2c084f19b38c70bd802bf032334 Mon Sep 17 00:00:00 2001 From: Sempai-07 Date: Sat, 11 Apr 2026 23:14:35 +0300 Subject: [PATCH 03/20] Update(User): removed the check due to the introduction of (Bot-to-Bot) --- src/structures/misc/User.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/structures/misc/User.js b/src/structures/misc/User.js index c6b9c48..f861ea6 100644 --- a/src/structures/misc/User.js +++ b/src/structures/misc/User.js @@ -21,9 +21,7 @@ class User extends Base { this.id = String(data.id); /** True, if this user is a bot */ - this.isBot = Boolean( - data.id == ("user" in client ? client.user?.id : 0) ? true : data.is_bot, - ); + this.isBot = data.is_bot; this._patch(data); } From 00268d1a895644a8be654e86127837b6de6d0e36 Mon Sep 17 00:00:00 2001 From: Sempai-07 Date: Fri, 17 Apr 2026 21:57:19 +0300 Subject: [PATCH 04/20] Fix(ManagerCached): fullInfo flag will be fetched instead of being taken from the cache of the regular User object --- src/managers/ChatManager.ts | 2 +- src/managers/UserManager.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/managers/ChatManager.ts b/src/managers/ChatManager.ts index a9474aa..05c14ff 100644 --- a/src/managers/ChatManager.ts +++ b/src/managers/ChatManager.ts @@ -90,7 +90,7 @@ class ChatManager extends BaseManager { ): Promise { const id = this.resolveId(this.resolve(chat)); - if (!force) { + if (!force && !fullInfo) { const existing = this.cache.get(String(id)); if (existing) return existing; } diff --git a/src/managers/UserManager.ts b/src/managers/UserManager.ts index 5c961f0..372d5dc 100644 --- a/src/managers/UserManager.ts +++ b/src/managers/UserManager.ts @@ -105,7 +105,7 @@ class UserManager extends BaseManager { ): Promise { const id = this.resolveId(this.resolve(user)); - if (!force) { + if (!force && !fullInfo) { const existing = this.cache.get(String(id)); if (existing) return existing; } From 9a63d3e1694e0b8d7e4062790380a8bff4b30273 Mon Sep 17 00:00:00 2001 From: Sempai-07 Date: Fri, 17 Apr 2026 22:45:31 +0300 Subject: [PATCH 05/20] Support api 9.4 --- README.md | 26 ++- src/client/BaseClient.ts | 35 +++- src/client/interfaces/Markup.ts | 12 +- src/client/interfaces/Methods.ts | 21 +- src/index.ts | 1 + src/structures/chat/Chat.js | 2 +- src/structures/chat/ChatFullInfo.js | 6 + src/structures/gift/UniqueGift.js | 12 +- src/structures/index.js | 3 + src/structures/media/Video.js | 12 ++ src/structures/media/VideoQuality.js | 23 +++ src/structures/message/Message.js | 16 ++ src/structures/misc/ClientUser.js | 22 ++- src/structures/misc/UserProfileAudios.js | 32 +++ src/util/Constants.ts | 10 + src/util/markup/InlineKeyboardBuilder.ts | 238 +++++++++++++++-------- src/util/markup/KeyboardBuilder.ts | 104 +++++++--- src/util/markup/utils.ts | 43 ++++ tsconfig.test.json | 2 +- typings/index.d.ts | 238 ++++++++++++++++++++--- typings/telegram/Markup.d.ts | 12 +- typings/telegram/Methods.d.ts | 21 +- 22 files changed, 744 insertions(+), 147 deletions(-) create mode 100644 src/structures/media/VideoQuality.js create mode 100644 src/structures/misc/UserProfileAudios.js create mode 100644 src/util/markup/utils.ts diff --git a/README.md b/README.md index d83a2d7..d206a60 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

Telegramsjs



-[![Bot API](https://img.shields.io/badge/Bot%20API-v.9.3-00aced.svg?style=flat-square&logo=telegram)](https://core.telegram.org/bots/api) +[![Bot API](https://img.shields.io/badge/Bot%20API-v.9.4-00aced.svg?style=flat-square&logo=telegram)](https://core.telegram.org/bots/api) [![NPM Version](https://img.shields.io/npm/v/telegramsjs.svg?maxAge=3600)](https://www.npmjs.com/package/telegramsjs) [![NPM Downloads](https://img.shields.io/npm/dt/telegramsjs.svg?maxAge=3600)](https://www.npmjs.com/package/telegramsjs) @@ -50,9 +50,9 @@ Afterwards we can create a quite simple example bot: ```js // ECMAscript/TypeScript -import { TelegramClient } from "telegramsjs"; +import { TelegramClient, InlineKeyboardBuilder, MarkupStyles } from "telegramsjs"; // CommonJS -const { TelegramClient } = require("telegramsjs"); +const { TelegramClient, InlineKeyboardBuilder, MarkupStyles } = require("telegramsjs"); const client = new TelegramClient("TELEGRAM_BOT_TOKEN"); @@ -74,6 +74,26 @@ client.on("message", async (message) => { ); return; } + + if (message.content === "/menu") { + const menu = new InlineKeyboardBuilder() + .text("Pay", "menu_pay", { + style: MarkupStyles.Green, + icon: "5463122435425448565", + }) + .text("Rules", "menu_rules", { + style: MarkupStyles.Danger, + icon: "5465154440287757794", + }).row() + .text("Home", "menu_home", { + style: MarkupStyles.Primary, + icon: "5253997076169115797", + }); + + await msg.chat.send("Payment panel", { + replyMarkup: menu, + }); + } }); client.login(); diff --git a/src/client/BaseClient.ts b/src/client/BaseClient.ts index 17748c2..baadda2 100644 --- a/src/client/BaseClient.ts +++ b/src/client/BaseClient.ts @@ -4,7 +4,7 @@ import { Collection } from "@telegram.ts/collection"; import { UserManager } from "../managers/UserManager"; import { ChatManager } from "../managers/ChatManager"; import type { LanguageCode } from "./interfaces/Language"; -import type { MediaDataParam } from "./interfaces/Methods"; +import type { MediaDataParam, InputProfilePhoto } from "./interfaces/Methods"; import type { ClientOptions, TelegramClient } from "./TelegramClient"; import { Message, @@ -14,6 +14,7 @@ import { WebhookInfo, UserChatBoosts, UserProfilePhotos, + UserProfileAudios, BusinessConnection, ChatAdministratorRights, InputFile, @@ -673,6 +674,17 @@ class BaseClient extends EventEmitter { .then((res) => new UserProfilePhotos(this, res)); } + /** Use this method to get a list of profile audios for a user. Returns a UserProfileAudios object. */ + async getUserProfileAudios( + params: MethodParameters["getUserProfileAudios"], + ): Promise { + return this.rest + .request< + MethodsApiReturnType["getUserProfileAudios"] + >("getUserProfileAudios", toSnakeCase(params)) + .then((res) => new UserProfileAudios(this, res)); + } + /** Changes the emoji status for a given user that previously allowed the bot to manage their emoji status via the Mini App method requestEmojiStatusAccess. Returns True on success. */ async setUserEmojiStatus( params: MethodParameters["setUserEmojiStatus"], @@ -1111,7 +1123,7 @@ class BaseClient extends EventEmitter { ); } - /** Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user. Requires no parameters. Returns an Array of Sticker objects. */ + /** Use this method to create a topic in a forum supergroup chat or a private chat with a user. In the case of a supergroup chat the bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator right. Returns information about the created topic as a ForumTopic object. */ async getForumTopicIconStickers(): Promise< MethodsLibReturnType["getForumTopicIconStickers"] > { @@ -1380,6 +1392,25 @@ class BaseClient extends EventEmitter { .then((res) => res.short_description); } + /** Changes the profile photo of the bot. Returns True on success. */ + async setMyProfilePhoto( + photo: InputProfilePhoto, + ): Promise { + return this.rest.request( + "setMyProfilePhoto", + { photo }, + ); + } + + /** Removes the profile photo of the bot. Requires no parameters. Returns True on success. */ + async removeMyProfilePhoto(): Promise< + MethodsApiReturnType["removeMyProfilePhoto"] + > { + return this.rest.request( + "removeMyProfilePhoto", + ); + } + /** Use this method to change the bot's menu button in a private chat, or the default menu button. Returns True on success. */ async setChatMenuButton( chatId?: string | number, diff --git a/src/client/interfaces/Markup.ts b/src/client/interfaces/Markup.ts index 55c1cf5..6e3ae18 100644 --- a/src/client/interfaces/Markup.ts +++ b/src/client/interfaces/Markup.ts @@ -10,6 +10,10 @@ export declare namespace InlineKeyboardButton { interface AbstractInlineKeyboardButton { /** Label text on the button */ text: string; + /** Unique identifier of the custom emoji shown before the text of the button. Can only be used by bots that purchased additional usernames on Fragment or in the messages directly sent by the bot to private, group and supergroup chats if the owner of the bot has a Telegram Premium subscription. */ + icon_custom_emoji_id?: string; + /** Style of the button. Must be one of “danger” (red), “success” (green) or “primary” (blue). If omitted, then an app-specific style is used. */ + style?: "danger" | "success" | "primary"; } export interface UrlButton extends AbstractInlineKeyboardButton { /** HTTP or tg:// URL to be opened when the button is pressed. Links tg://user?id= can be used to mention a user by their ID without using a username, if this is allowed by their privacy settings. */ @@ -151,8 +155,12 @@ export interface ReplyKeyboardMarkup { export declare namespace KeyboardButton { export interface CommonButton { - /** Text of the button. If none of the optional fields are used, it will be sent as a message when the button is pressed */ + /** Text of the button. If none of the fields other than text, icon_custom_emoji_id, and style are used, it will be sent as a message when the button is pressed */ text: string; + /** Unique identifier of the custom emoji shown before the text of the button. Can only be used by bots that purchased additional usernames on Fragment or in the messages directly sent by the bot to private, group and supergroup chats if the owner of the bot has a Telegram Premium subscription. */ + icon_custom_emoji_id?: string; + /** Style of the button. Must be one of “danger” (red), “success” (green) or “primary” (blue). If omitted, then an app-specific style is used. */ + style?: "danger" | "success" | "primary"; } export interface RequestUsersButton extends CommonButton { /** If specified, pressing the button will open a list of suitable users. Identifiers of selected users will be sent to the bot in a “users_shared” service message. Available in private chats only. */ @@ -180,7 +188,7 @@ export declare namespace KeyboardButton { } } -/** This object represents one button of the reply keyboard. At most one of the optional fields must be used to specify type of the button. For simple text buttons, String can be used instead of this object to specify the button text. */ +/** This object represents one button of the reply keyboard. At most one of the fields other than text, icon_custom_emoji_id, and style must be used to specify the type of the button. For simple text buttons, String can be used instead of this object to specify the button text. */ export type KeyboardButton = | KeyboardButton.CommonButton | KeyboardButton.RequestUsersButton diff --git a/src/client/interfaces/Methods.ts b/src/client/interfaces/Methods.ts index e304e4e..2dabd29 100644 --- a/src/client/interfaces/Methods.ts +++ b/src/client/interfaces/Methods.ts @@ -1119,6 +1119,16 @@ export type ApiMethods = { limit?: number; }): import("../../structures/misc/UserProfilePhotos").UserProfilePhotos; + /** Use this method to get a list of profile audios for a user. Returns a UserProfileAudios object. */ + getUserProfileAudios(args: { + /** Unique identifier of the target user */ + userId: string | number; + /** Sequential number of the first audio to be returned. By default, all audios are returned. */ + offset?: number; + /** Limits the number of audios to be retrieved. Values between 1-100 are accepted. Defaults to 100. */ + limit?: number; + }): import("../../structures/misc/UserProfileAudios").UserProfileAudios; + /** Changes the emoji status for a given user that previously allowed the bot to manage their emoji status via the Mini App method requestEmojiStatusAccess. Returns True on success. */ setUserEmojiStatus(args: { /** Unique identifier of the target user */ @@ -1433,7 +1443,7 @@ export type ApiMethods = { /** Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user. Requires no parameters. Returns an Array of Sticker objects. */ getForumTopicIconStickers(): import("../../structures/media/Sticker").Sticker[]; - /** Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. Returns information about the created topic as a ForumTopic object. */ + /** Use this method to create a topic in a forum supergroup chat or a private chat with a user. In the case of a supergroup chat the bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator right. Returns information about the created topic as a ForumTopic object. */ createForumTopic(args: { /** Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) */ chatId: number | string; @@ -1675,6 +1685,15 @@ export type ApiMethods = { languageCode?: LanguageCode; }): string; + /** Changes the profile photo of the bot. Returns True on success. */ + setMyProfilePhoto(args: { + /** The new profile photo to set */ + photo: InputProfilePhoto; + }): true; + + /** Removes the profile photo of the bot. Requires no parameters. Returns True on success. */ + removeMyProfilePhoto(): true; + /** Use this method to change the bot's menu button in a private chat, or the default menu button. Returns True on success. */ setChatMenuButton(args: { /** Unique identifier for the target private chat. If not specified, default bot's menu button will be changed */ diff --git a/src/index.ts b/src/index.ts index d1aaef8..49f9c51 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,7 @@ export * from "./util/inline/InlineQueryResultCachedBuilder"; export * from "./util/inline/InputMessageContentBuilder"; export * from "./util/markup/InlineKeyboardBuilder"; export * from "./util/markup/KeyboardBuilder"; +export { type MarkupOptions } from "./util/markup/utils"; export * from "./util/permission/ChatPermissions"; export * from "./util/permission/UserPermissions"; export * from "./util/permission/BusinessPermissions"; diff --git a/src/structures/chat/Chat.js b/src/structures/chat/Chat.js index 9779915..71b613a 100644 --- a/src/structures/chat/Chat.js +++ b/src/structures/chat/Chat.js @@ -495,7 +495,7 @@ class Chat extends Base { } /** - * Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. + * Use this method to create a topic in a forum supergroup chat or a private chat with a user. In the case of a supergroup chat the bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator right. * @param {string} name - Topic name, 1-128 characters * @param {Omit} [options={}] - out parameters * @returns {Promise} - Returns information about the created topic as a ForumTopic object. diff --git a/src/structures/chat/ChatFullInfo.js b/src/structures/chat/ChatFullInfo.js index a3213a4..d4bd017 100644 --- a/src/structures/chat/ChatFullInfo.js +++ b/src/structures/chat/ChatFullInfo.js @@ -3,6 +3,7 @@ const { Chat } = require("./Chat"); const { Photo } = require("../media/Photo"); const { Location } = require("../misc/Location"); const { Sticker } = require("../media/Sticker"); +const { Audio } = require("../media/Audio"); const { ReactionType } = require("../misc/ReactionType"); const { UserRating } = require("../misc/UserRating"); const { Message } = require("../message/Message"); @@ -101,6 +102,11 @@ class ChatFullInfo extends Chat { }; } + if ("first_profile_audio" in data && data.first_profile_audio) { + /** For private chats, the first audio added to the profile of the user */ + this.firstProfileAudio = new Audio(this.client, data.first_profile_audio); + } + if ("active_usernames" in data) { /** * The active usernames of the chat. diff --git a/src/structures/gift/UniqueGift.js b/src/structures/gift/UniqueGift.js index a4deb6b..60ce095 100644 --- a/src/structures/gift/UniqueGift.js +++ b/src/structures/gift/UniqueGift.js @@ -47,7 +47,7 @@ class UniqueGift extends Base { name: data.model.name, /** The sticker that represents the unique gift */ sticker: new Sticker(client, data.model.sticker), - /** The number of unique gifts that receive this model for every 1000 gifts upgraded */ + /** The number of unique gifts that receive this model for every 1000 gift upgrades. Always 0 for crafted gifts */ rarityPerMille: data.model.rarity_per_mille, }; @@ -57,7 +57,7 @@ class UniqueGift extends Base { name: data.symbol.name, /** The sticker that represents the unique gift */ sticker: new Sticker(client, data.symbol.sticker), - /** The number of unique gifts that receive this model for every 1000 gifts upgraded */ + /** The number of unique gifts that receive this model for every 1000 gift upgrades. Always 0 for crafted gifts */ rarityPerMille: data.symbol.rarity_per_mille, }; @@ -103,6 +103,11 @@ class UniqueGift extends Base { }, }; } + + if ("is_burned" in data) { + /** True, if the gift was used to craft another gift and isn't available anymore */ + this.isBurned = data.is_burned; + } } /** @@ -123,7 +128,8 @@ class UniqueGift extends Base { isDeepStrictEqual(this.model, other.model) && isDeepStrictEqual(this.symbol, other.symbol) && isDeepStrictEqual(this.backdrop, other.backdrop) && - isDeepStrictEqual(this.colors, other.colors) + isDeepStrictEqual(this.colors, other.colors) && + this.isBurned === other.isBurned ); } } diff --git a/src/structures/index.js b/src/structures/index.js index d6b4349..faef8c9 100644 --- a/src/structures/index.js +++ b/src/structures/index.js @@ -111,6 +111,7 @@ module.exports.Sticker = require("./media/Sticker").Sticker; module.exports.StickerSet = require("./media/StickerSet").StickerSet; module.exports.Video = require("./media/Video").Video; module.exports.VideoNote = require("./media/VideoNote").VideoNote; +module.exports.VideoQuality = require("./media/VideoQuality").VideoQuality; module.exports.Voice = require("./media/Voice").Voice; module.exports.Message = require("./message/Message").Message; module.exports.MessageEntities = @@ -133,6 +134,8 @@ module.exports.SharedUser = require("./misc/SharedUser").SharedUser; module.exports.StarAmount = require("./misc/StarAmount").StarAmount; module.exports.TextQuote = require("./misc/TextQuote").TextQuote; module.exports.User = require("./misc/User").User; +module.exports.UserProfileAudios = + require("./misc/UserProfileAudios").UserProfileAudios; module.exports.UserProfilePhotos = require("./misc/UserProfilePhotos").UserProfilePhotos; module.exports.UsersShared = require("./misc/UsersShared").UsersShared; diff --git a/src/structures/media/Video.js b/src/structures/media/Video.js index 267ce7a..9789470 100644 --- a/src/structures/media/Video.js +++ b/src/structures/media/Video.js @@ -1,5 +1,7 @@ // @ts-check const { Photo } = require("./Photo"); +const { Collection } = require("@telegram.ts/collection"); +const { VideoQuality } = require("./VideoQuality"); const { InputFile } = require("../misc/InputFile"); class Video extends InputFile { @@ -43,6 +45,16 @@ class Video extends InputFile { /** MIME type of the file as defined by sender */ this.mimeType = data.mime_type; } + + if ("qualities" in data) { + /** List of available qualities of the video. */ + this.qualities = new Collection( + data.qualities.map((quality) => [ + quality.file_id, + new VideoQuality(client, quality), + ]), + ); + } } /** diff --git a/src/structures/media/VideoQuality.js b/src/structures/media/VideoQuality.js new file mode 100644 index 0000000..746a943 --- /dev/null +++ b/src/structures/media/VideoQuality.js @@ -0,0 +1,23 @@ +// @ts-check +const { InputFile } = require("../misc/InputFile"); + +class VideoQuality extends InputFile { + /** + * @param {import("../../client/TelegramClient").TelegramClient | import("../../client/BaseClient").BaseClient} client - The client that instantiated this + * @param {import("@telegram.ts/types").VideoQuality} data - Data about the represents video file of a specific quality + */ + constructor(client, data) { + super(client, data); + + /** Photo width */ + this.width = data.width; + + /** Photo height */ + this.height = data.height; + + /** Codec that was used to encode the video, for example, “h264”, “h265”, or “av01” */ + this.codec = data.codec; + } +} + +module.exports = { VideoQuality }; diff --git a/src/structures/message/Message.js b/src/structures/message/Message.js index cf760bd..a80218f 100644 --- a/src/structures/message/Message.js +++ b/src/structures/message/Message.js @@ -923,6 +923,22 @@ class Message extends Base { ); } + if ("chat_owner_left" in data && data.chat_owner_left?.new_owner) { + /** + * Service message: chat owner has left + */ + this.ownerLeft = this.client.users._add(data.chat_owner_left.new_owner); + } + + if ("chat_owner_changed" in data) { + /** + * Service message: chat owner has changed + */ + this.ownerChanged = this.client.users._add( + data.chat_owner_changed.new_owner, + ); + } + if ("suggested_post_refunded" in data) { /** * Service message: payment for a suggested post was refunded diff --git a/src/structures/misc/ClientUser.js b/src/structures/misc/ClientUser.js index 43f630b..0f7225d 100644 --- a/src/structures/misc/ClientUser.js +++ b/src/structures/misc/ClientUser.js @@ -34,9 +34,12 @@ class ClientUser extends User { /** Indicates if the bot has a main Web App */ this.mainWebApp = data.has_main_web_app; - /** True, if the bot has forum topic mode enabled in private chats. Returned only in getMe. */ + /** True, if the bot has forum topic mode enabled in private chats */ this.topicsEnabled = data.has_topics_enabled; + /** True, if the bot allows users to create and delete topics in private chats */ + this.allowUserTopicCreation = data.allows_users_to_create_topics; + this._patch(data); } @@ -181,6 +184,23 @@ class ClientUser extends User { return this.client.getMyShortDescription(language); } + /** + * Changes the profile photo of the bot. + * @param {import("../../client/interfaces/Methods").InputProfilePhoto} photo - The new profile photo to set. + * @returns {Promise} - Returns True on success. + **/ + setProfilePhoto(photo) { + return this.client.setMyProfilePhoto(photo); + } + + /** + * Removes the profile photo of the bot. + * @returns {Promise} - Returns True on success. + **/ + removeProfilePhoto() { + return this.client.removeMyProfilePhoto(); + } + /** * Use this method to change the bot's menu button in a private chat, or the default menu button. * @param {number} [chatId] - Unique identifier for the target private chat. If not specified, default bot's menu button will be changed diff --git a/src/structures/misc/UserProfileAudios.js b/src/structures/misc/UserProfileAudios.js new file mode 100644 index 0000000..6b0d113 --- /dev/null +++ b/src/structures/misc/UserProfileAudios.js @@ -0,0 +1,32 @@ +// @ts-check +const { Base } = require("../Base"); +const { Audio } = require("../media/Audio"); +const { Collection } = require("@telegram.ts/collection"); + +class UserProfileAudios extends Base { + /** + * @param {import("../../client/TelegramClient").TelegramClient | import("../../client/BaseClient").BaseClient} client - The client that instantiated this + * @param {import("@telegram.ts/types").UserProfileAudios} data - Data about the audios displayed on a user's profile + */ + constructor(client, data) { + super(client); + + /** Total number of profile audios for the target user */ + this.count = data.total_count; + + /** Requested profile audios */ + this.audios = new Collection( + data.audios.map((audio) => [audio.file_id, new Audio(client, audio)]), + ); + } + + /** + * Makes the class iterable, returning each `Audio` object. + * @returns {IterableIterator