Сообщить об ошибке.

Тип Chats против Channels в модуле Telethon

Необработанный API Telegram может сбивать с толку, особенно когда речь идет о "чатах", "каналах", "группах", "мегагруппах" и всех этих понятиях.

В этом разделе объясняется, что представляет собой каждое из этих понятий.

Содержание:


Понятие "Chat"

Chat можно использовать для обсуждения любых общих тем "подкласса", который используется как для чатов, так и для каналов, либо для конкретного типа Chat.

Технически и Chat, и Channels являются разновидностью типа Chat.

В большинстве случаев термин *Chat* используется для обозначения небольших групповых чатов. Когда создается группа через официальное приложение, то получается именно такой тип. В официальных приложениях они называются "Группой".

И API бота, и Telethon добавят знак минус (-) к реальному идентификатору чата, чтобы можно было с первого взгляда определить тип объекта с помощью числа.

Например, если создается чат с помощью functions.messages.CreateChatRequest, реальный идентификатор чата может быть, например, 123. Если распечатать его из message.chat_id, то увидим -123. Этот идентификатор помогает Telethon понять, что речь идет о чате.

from telethon.sync import TelegramClient
from telethon import functions

with TelegramClient(name, api_id, api_hash) as client:
    result = client(functions.messages.CreateChatRequest(
        users=['username'],
        title='My awesome title',
        ttl_period=42
    ))
    print(result.stringify())

Понятие "Channel"

Официальные приложения создают канал трансляции при создании нового канала (используется для трансляции сообщений, сообщения могут публиковать только администраторы).

Официальные приложения неявно переносят существующий Chat в Channel мегагруппы, когда выполняются определенные действия (превышается лимит пользователей, добавляется общедоступное имя пользователя, устанавливаются определенные разрешения и т. д.).

Канал можно создать непосредственно с помощью functions.messages.CreateChannelRequest как мегагруппу или трансляцию.

Официальные приложения используют термин Channel только для каналов вещания.

API относится к различным типам каналов с определенными атрибутами:

  • Широковещательный канал - это канал с атрибутом channel.broadcast, установленным в значение True.
  • Канал мегагруппы - это канал с атрибутом channel.megagroup, установленным в значение True. В официальных приложениях это называется "супергруппой".
  • Канал гигагруппы - это канал с атрибутом channel.gigagroup, установленным в значение True. В официальных приложениях это называется "широковещательными группами" и используется, когда мегагруппа становится очень большой и администраторы хотят превратить ее во что-то, где только они могут публиковать сообщения.

И API бота, и Telethon "объединят" -100 с реальным идентификатором чата, чтобы можно было с первого взгляда определить тип объекта по номеру.

Например, если создается новый широковещательный канал, то реальный идентификатор канала может быть, например, 456. Если распечатать его из message.chat_id, увидим -1000000000456. Этот идентификатор помогает Telethon понять, что речь идет о канале.

Преобразование идентификаторов

Можно конвертировать между "помеченными" идентификаторами (со знаком минус) и реальными с помощью utils.resolve_id(). Метод вернет кортеж с реальным идентификатором и типом узла (классом):

from telethon import utils
real_id, peer_type = utils.resolve_id(-1000000000456)

print(real_id)  
# 456
print(peer_type)  
# <class 'telethon.tl.types.PeerChannel'>

peer = peer_type(real_id)
print(peer)  
# PeerChannel(channel_id=456)

Обратная операция может быть выполнена с помощью utils.get_peer_id():

print(utils.get_peer_id(types.PeerChannel(456)))  
# -1000000000456

Обратите внимание, что эта функция также может работать с другими типами, такими как экземпляры чата или канала.

Если нужно преобразовать другие типы, такие как имена пользователей, которым, возможно, потребуется выполнить вызовы API для определения идентификатора, то необходимо использовать client.get_peer_id():

print(await client.get_peer_id('me'))  
# напечатает собственный ID

Если "пометки" (знак минус) НЕТ, то Telethon будет считать, что идентификатор относится к типу User. Если это не так, то это можно исправить вручную:

from telethon import types
# явный тип узла
await client.send_message(types.PeerChannel(456), 'hello')

Примечание по необработанному API

Некоторые методы работают только c типом Chat, а некоторые другие работают только с Channel (т.е. работают только в трансляции или мегагруппе). Скорее всего код знает, с чем работает, поэтому это не должно быть большой проблемой.

Если все таки нужно найти канал из чата, который был перенесен на него, то необходимо использовать chat.migrated_to:

# chat это `Chat`
channel = await client.get_entity(chat.migrated_to)
# channel теперь является `Channel`

У типа Channel нет метода .migrated_from, но у ChannelFull есть. Можно использовать GetFullChannelRequest, чтобы это получить:

from telethon import functions
full = await client(functions.channels.GetFullChannelRequest(your_channel))
full_channel = full.full_chat
# переменная `full_channel` - имеет тип `ChannelFull`
print(full_channel.migrated_from_chat_id)

Таким образом, также можно получить доступ к связанной дискуссионной мегагруппе вещательного канала:

# выводит идентификатор связанной дискуссионной группы или `None`
print(full_channel.linked_chat_id)

Не нужно использовать метод client.get_entity() для доступа к чату migred_from_chat_id или каналу linked_chat_id. Они находятся в атрибуте full.chats:

if full_channel.migrated_from_chat_id:
    migrated_from_chat = next(c for c in full.chats if c.id == full_channel.migrated_from_chat_id)
    print(migrated_from_chat.title)

if full_channel.linked_chat_id:
    linked_group = next(c for c in full.chats if c.id == full_channel.linked_chat_id)
    print(linked_group.username)