ferogram 0.2.1__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ferogram-0.2.3/CHANGELOG.md +65 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/Cargo.lock +23 -23
- {ferogram-0.2.1 → ferogram-0.2.3}/Cargo.toml +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/FEATURES.md +320 -26
- {ferogram-0.2.1 → ferogram-0.2.3}/PKG-INFO +1 -1
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/__init__.py +6 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/client.py +305 -13
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/__init__.py +2 -1
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/codegen.py +28 -3
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/__init__.py +2 -1
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/_tl_schema.py +61 -17
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/__init__.py +5 -2
- ferogram-0.2.3/ferogram/raw/generated/functions/aicompose.py +173 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/bots.py +44 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/contacts.py +5 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/messages.py +101 -5
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/stats.py +26 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/__init__.py +5 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/_base.py +245 -4
- ferogram-0.2.3/ferogram/raw/generated/types/aicompose.py +58 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/auth.py +5 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/bots.py +23 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/stats.py +20 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/types.py +23 -3
- {ferogram-0.2.1 → ferogram-0.2.3}/pyproject.toml +1 -1
- ferogram-0.2.3/src/auth.rs +222 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/src/client.rs +421 -44
- ferogram-0.2.3/src/keyboards.rs +567 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/src/lib.rs +8 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/src/updates.rs +17 -0
- ferogram-0.2.1/src/auth.rs +0 -82
- {ferogram-0.2.1 → ferogram-0.2.3}/.github/workflows/publish.yml +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/.gitignore +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/LICENSE-APACHE +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/LICENSE-MIT +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/README.md +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/admin_tools.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/command_bot.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/echo_bot.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/group_management.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/media_bot.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/raw_invoke.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/search_bot.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/send_hi.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/send_media.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/send_message.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/update_handlers.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/user_management.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/examples/userbot.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/filters.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/logging.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/py.typed +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/api/__init__.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/api/functions.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/api/types.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/account.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/auth.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/channels.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/chatlists.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/folders.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/fragment.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/help.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/langpack.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/payments.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/phone.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/photos.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/premium.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/smsjobs.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/stickers.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/stories.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/updates.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/upload.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/functions/users.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/account.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/channels.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/chatlists.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/contacts.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/fragment.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/help.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/messages.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/payments.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/phone.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/photos.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/premium.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/smsjobs.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/stickers.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/storage.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/stories.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/updates.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/upload.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/generated/types/users.py +2 -2
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/proxy.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw/tl.py +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/ferogram/raw_api.tl +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/src/message.rs +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/src/raw.rs +0 -0
- {ferogram-0.2.1 → ferogram-0.2.3}/src/types.rs +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.3 (2026-05-14)
|
|
4
|
+
|
|
5
|
+
### Client Builder
|
|
6
|
+
|
|
7
|
+
Added 20 new kwargs to `Client(...)` so you can configure everything at construction time instead of touching internals.
|
|
8
|
+
|
|
9
|
+
Network options: `proxy` (SOCKS5 or MTProxy t.me link), `allow_ipv6`, `dc_addr`, `probe_transport`, `resilient_connect`.
|
|
10
|
+
|
|
11
|
+
Session backend: `session_string` and `in_memory` as alternatives to the default session file. Priority is `in_memory > session_string > file`.
|
|
12
|
+
|
|
13
|
+
Update handling: `catch_up`, `pfs`, `update_queue_capacity`, `update_overflow` (`"drop_oldest"` or `"drop_newest"`), `low_memory_mode`.
|
|
14
|
+
|
|
15
|
+
InitConnection identity: `device`, `system_version`, `app_version`, `lang_code`, `system_lang_code`, `lang_pack`.
|
|
16
|
+
|
|
17
|
+
Experimental: `allow_missing_channel_hash`, `auto_resolve_peers`.
|
|
18
|
+
|
|
19
|
+
### Inline Bots
|
|
20
|
+
|
|
21
|
+
`InlineArticle`, `InlinePhoto`, and `InlineDocument` now expose all their fields. Previously only the 3 required fields worked. New fields: `description`, `url`, `thumb_url`, `reply_markup` on articles; `photo_url`, `photo_width`, `photo_height`, `thumb_url`, `mime_type`, `reply_markup` on photos; `document_url`, `mime_type`, `description`, `thumb_url`, `reply_markup` on documents.
|
|
22
|
+
|
|
23
|
+
`answer_inline_query` now accepts `next_offset` for pagination and `switch_pm` to show a "go to PM" button in the results list.
|
|
24
|
+
|
|
25
|
+
`answer_inline_query_articles` is now accessible from Python. Takes a plain list of `(id, title, text)` tuples and supports `next_offset`.
|
|
26
|
+
|
|
27
|
+
`edit_inline_message` now accepts `reply_markup` so you can attach or update a keyboard when editing.
|
|
28
|
+
|
|
29
|
+
`InlineSend` now exposes `msg_id_bytes` and `msg_id_dc` so you can build an `InlineMessageId` from the send event and edit the message later.
|
|
30
|
+
|
|
31
|
+
### Participants
|
|
32
|
+
|
|
33
|
+
Ten new methods for managing group and channel members.
|
|
34
|
+
|
|
35
|
+
`get_participants(peer, limit=200)` fetches all members as a list of `ChatMember`.
|
|
36
|
+
|
|
37
|
+
`get_participants_filtered(peer, filter, limit)` fetches a filtered subset. Filter values: `"recent"`, `"admins"`, `"kicked"`, `"banned"`, `"bots"`.
|
|
38
|
+
|
|
39
|
+
`kick_participant(peer, user)` removes a user from the chat. They can rejoin if the chat is public or they have an invite link.
|
|
40
|
+
|
|
41
|
+
`ban_participant(peer, user)` permanently bans a user until an admin manually lifts it.
|
|
42
|
+
|
|
43
|
+
`ban_participant_until(peer, user, until_date)` bans until a unix timestamp, after which the ban lifts automatically.
|
|
44
|
+
|
|
45
|
+
`promote_participant(peer, user, rights)` promotes to admin with specific rights. Pass `rights=None` to grant all. Valid right strings: `"change_info"`, `"post_messages"`, `"edit_messages"`, `"delete_messages"`, `"ban_users"`, `"invite_users"`, `"pin_messages"`, `"add_admins"`, `"manage_call"`.
|
|
46
|
+
|
|
47
|
+
`demote_participant(peer, user)` strips all admin rights, leaving the user as a regular member.
|
|
48
|
+
|
|
49
|
+
`get_profile_photos(peer, limit=100)` returns a list of `(file_id, access_hash, dc_id)` tuples.
|
|
50
|
+
|
|
51
|
+
`search_peer(query)` searches the local peer cache by name or username and returns a list of peer identifier strings.
|
|
52
|
+
|
|
53
|
+
`signal_network_restored()` (sync, not async) tells the client network is back so it attempts reconnect immediately instead of waiting for the retry timer.
|
|
54
|
+
|
|
55
|
+
### Reactions and Polls
|
|
56
|
+
|
|
57
|
+
`delete_reaction(peer, msg_id, participant)` was in Rust but had no Python wrapper. Now exposed. Removes a specific user's reaction from a message, admin only.
|
|
58
|
+
|
|
59
|
+
`get_poll_results(peer, msg_id, poll_hash)` was in Rust but had no Python wrapper. Now exposed. Fetches and caches the latest poll results from Telegram.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 0.2.2
|
|
64
|
+
|
|
65
|
+
Previous release.
|
|
@@ -274,9 +274,9 @@ dependencies = [
|
|
|
274
274
|
|
|
275
275
|
[[package]]
|
|
276
276
|
name = "ferogram"
|
|
277
|
-
version = "0.4.
|
|
277
|
+
version = "0.4.1"
|
|
278
278
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
279
|
-
checksum = "
|
|
279
|
+
checksum = "0b72cbc599397f85947c77d7807db9b40baa047598ef17fb7b3425adf980ce48"
|
|
280
280
|
dependencies = [
|
|
281
281
|
"async-trait",
|
|
282
282
|
"base64",
|
|
@@ -314,9 +314,9 @@ dependencies = [
|
|
|
314
314
|
|
|
315
315
|
[[package]]
|
|
316
316
|
name = "ferogram-connect"
|
|
317
|
-
version = "0.4.
|
|
317
|
+
version = "0.4.1"
|
|
318
318
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
319
|
-
checksum = "
|
|
319
|
+
checksum = "48614f5825a4e069d8daf80998d0bda2c02b7e92e6116c789054ceef82568fd1"
|
|
320
320
|
dependencies = [
|
|
321
321
|
"ferogram-crypto",
|
|
322
322
|
"ferogram-mtproto",
|
|
@@ -334,9 +334,9 @@ dependencies = [
|
|
|
334
334
|
|
|
335
335
|
[[package]]
|
|
336
336
|
name = "ferogram-crypto"
|
|
337
|
-
version = "0.4.
|
|
337
|
+
version = "0.4.1"
|
|
338
338
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
339
|
-
checksum = "
|
|
339
|
+
checksum = "7e27eef45ed7600e3b93442602f1acbc82c86cbbd8be33395c64962333f4a9fe"
|
|
340
340
|
dependencies = [
|
|
341
341
|
"aes",
|
|
342
342
|
"ctr",
|
|
@@ -349,9 +349,9 @@ dependencies = [
|
|
|
349
349
|
|
|
350
350
|
[[package]]
|
|
351
351
|
name = "ferogram-fsm"
|
|
352
|
-
version = "0.4.
|
|
352
|
+
version = "0.4.1"
|
|
353
353
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
354
|
-
checksum = "
|
|
354
|
+
checksum = "b06529ae56dbc45a50f10709572fa127c5c2a58132f4b1eaa90c826e51ae40a6"
|
|
355
355
|
dependencies = [
|
|
356
356
|
"async-trait",
|
|
357
357
|
"dashmap",
|
|
@@ -362,9 +362,9 @@ dependencies = [
|
|
|
362
362
|
|
|
363
363
|
[[package]]
|
|
364
364
|
name = "ferogram-mtproto"
|
|
365
|
-
version = "0.4.
|
|
365
|
+
version = "0.4.1"
|
|
366
366
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
367
|
-
checksum = "
|
|
367
|
+
checksum = "f14d5196b3f81974f7f990c822475354af4dd46a0d49c2d648e492c6084105a5"
|
|
368
368
|
dependencies = [
|
|
369
369
|
"ferogram-crypto",
|
|
370
370
|
"ferogram-tl-types",
|
|
@@ -377,9 +377,9 @@ dependencies = [
|
|
|
377
377
|
|
|
378
378
|
[[package]]
|
|
379
379
|
name = "ferogram-mtsender"
|
|
380
|
-
version = "0.4.
|
|
380
|
+
version = "0.4.1"
|
|
381
381
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
382
|
-
checksum = "
|
|
382
|
+
checksum = "f884b7cf4ff1a380559b057f569d6d884ec74405fda6f97ba79265f42ab22b3b"
|
|
383
383
|
dependencies = [
|
|
384
384
|
"ferogram-connect",
|
|
385
385
|
"ferogram-crypto",
|
|
@@ -397,9 +397,9 @@ dependencies = [
|
|
|
397
397
|
|
|
398
398
|
[[package]]
|
|
399
399
|
name = "ferogram-parsers"
|
|
400
|
-
version = "0.4.
|
|
400
|
+
version = "0.4.1"
|
|
401
401
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
402
|
-
checksum = "
|
|
402
|
+
checksum = "699accf665ae781947b041f9400f1a388ede032feb0a84c97247f1e6a79e1d31"
|
|
403
403
|
dependencies = [
|
|
404
404
|
"ferogram-tl-types",
|
|
405
405
|
"pulldown-cmark",
|
|
@@ -407,7 +407,7 @@ dependencies = [
|
|
|
407
407
|
|
|
408
408
|
[[package]]
|
|
409
409
|
name = "ferogram-py"
|
|
410
|
-
version = "0.2.
|
|
410
|
+
version = "0.2.3"
|
|
411
411
|
dependencies = [
|
|
412
412
|
"ferogram",
|
|
413
413
|
"hex",
|
|
@@ -418,9 +418,9 @@ dependencies = [
|
|
|
418
418
|
|
|
419
419
|
[[package]]
|
|
420
420
|
name = "ferogram-session"
|
|
421
|
-
version = "0.4.
|
|
421
|
+
version = "0.4.1"
|
|
422
422
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
423
|
-
checksum = "
|
|
423
|
+
checksum = "672fed4cda1078020cdfe3b0a76408224ba4dc265b26093d02342777d68cfb5f"
|
|
424
424
|
dependencies = [
|
|
425
425
|
"base64",
|
|
426
426
|
"tracing",
|
|
@@ -428,24 +428,24 @@ dependencies = [
|
|
|
428
428
|
|
|
429
429
|
[[package]]
|
|
430
430
|
name = "ferogram-tl-gen"
|
|
431
|
-
version = "0.4.
|
|
431
|
+
version = "0.4.1"
|
|
432
432
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
433
|
-
checksum = "
|
|
433
|
+
checksum = "b2c5767cecedb0e1df8f7c53f4dc1bfe0a3b686eb89bf4da26fa2d610e04fe8e"
|
|
434
434
|
dependencies = [
|
|
435
435
|
"ferogram-tl-parser",
|
|
436
436
|
]
|
|
437
437
|
|
|
438
438
|
[[package]]
|
|
439
439
|
name = "ferogram-tl-parser"
|
|
440
|
-
version = "0.4.
|
|
440
|
+
version = "0.4.1"
|
|
441
441
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
442
|
-
checksum = "
|
|
442
|
+
checksum = "9b655e882facfe8fb8326b4c63ac511089ce89f38c6b208111004256e2888483"
|
|
443
443
|
|
|
444
444
|
[[package]]
|
|
445
445
|
name = "ferogram-tl-types"
|
|
446
|
-
version = "0.4.
|
|
446
|
+
version = "0.4.1"
|
|
447
447
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
448
|
-
checksum = "
|
|
448
|
+
checksum = "ed947864a8bdea862a8336a691d957f2ab8dfd8d08063a90d77d0b70f753705f"
|
|
449
449
|
dependencies = [
|
|
450
450
|
"ferogram-tl-gen",
|
|
451
451
|
"ferogram-tl-parser",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "ferogram-py"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.3"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
description = "Python bindings for ferogram (Rust MTProto)"
|
|
6
6
|
license = "MIT OR Apache-2.0"
|
|
@@ -12,7 +12,7 @@ crate-type = ["cdylib"]
|
|
|
12
12
|
|
|
13
13
|
[dependencies]
|
|
14
14
|
hex = "0.4"
|
|
15
|
-
ferogram = "0.4.
|
|
15
|
+
ferogram = "0.4.1"
|
|
16
16
|
pyo3 = { version = "0.24", features = ["extension-module", "abi3-py313"] }
|
|
17
17
|
pyo3-async-runtimes = { version = "0.24", features = ["tokio-runtime"] }
|
|
18
18
|
tokio = { version = "1", features = ["full"] }
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Python bindings for the ferogram MTProto client.
|
|
4
4
|
|
|
5
|
-
All client methods are async. The `peer` parameter accepts "@username"
|
|
5
|
+
All client methods are async. The `peer` parameter accepts `"@username"`, `"me"`, or a numeric ID (int or string).
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
## Imports
|
|
@@ -16,9 +16,12 @@ from ferogram import ChatAction
|
|
|
16
16
|
from ferogram import InlineArticle, InlinePhoto, InlineDocument
|
|
17
17
|
from ferogram import InlineMessageId
|
|
18
18
|
from ferogram import PrivacyKey, PrivacyRule
|
|
19
|
+
from ferogram import InlineButton, InlineKeyboard
|
|
20
|
+
from ferogram import ReplyButton, ReplyKeyboard
|
|
21
|
+
from ferogram import RemoveKeyboard, ForceReply
|
|
19
22
|
```
|
|
20
23
|
|
|
21
|
-
Raw API usage (four styles, see the [Raw API](
|
|
24
|
+
Raw API usage (four styles, see the [Raw API](#raw-api) section for details):
|
|
22
25
|
|
|
23
26
|
```python
|
|
24
27
|
# style 1: namespace proxy, no extra import needed
|
|
@@ -59,6 +62,55 @@ async with app as client:
|
|
|
59
62
|
|
|
60
63
|
Credentials can also come from env vars: `API_ID`, `API_HASH`, `BOT_TOKEN`.
|
|
61
64
|
|
|
65
|
+
### Full init signature
|
|
66
|
+
|
|
67
|
+
These are all the kwargs you can pass to `Client(...)`. Most of them you will never need, but they are all there.
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
app = Client(
|
|
71
|
+
session="mybot", # session file name (no .session extension)
|
|
72
|
+
api_id=123456,
|
|
73
|
+
api_hash="abc...",
|
|
74
|
+
bot_token="123:TOKEN", # omit for userbot
|
|
75
|
+
phone="+1234567890", # for userbot interactive login
|
|
76
|
+
password="2fa_password", # 2FA password if set
|
|
77
|
+
|
|
78
|
+
# Network
|
|
79
|
+
proxy=None, # "socks5://host:port" or an MTProxy t.me link
|
|
80
|
+
allow_ipv6=False, # connect over IPv6 when available
|
|
81
|
+
dc_addr=None, # override DC address, e.g. "149.154.167.51:443"
|
|
82
|
+
probe_transport=False, # try multiple transports on first connect
|
|
83
|
+
resilient_connect=False, # keep retrying on initial connect failure
|
|
84
|
+
|
|
85
|
+
# Session backend (priority: in_memory > session_string > session file)
|
|
86
|
+
session_string=None, # base64 session string instead of file
|
|
87
|
+
in_memory=False, # ephemeral session, nothing written to disk
|
|
88
|
+
|
|
89
|
+
# Sync and updates
|
|
90
|
+
catch_up=False, # fetch missed updates on reconnect
|
|
91
|
+
pfs=False, # Perfect Forward Secrecy for the session
|
|
92
|
+
update_queue_capacity=None, # max pending updates before overflow kicks in
|
|
93
|
+
update_overflow=None, # "drop_oldest" or "drop_newest"
|
|
94
|
+
low_memory_mode=False, # smaller update queue, saves RAM on constrained devices
|
|
95
|
+
|
|
96
|
+
# InitConnection identity
|
|
97
|
+
device=None, # device model string sent in InitConnection
|
|
98
|
+
system_version=None, # OS version string
|
|
99
|
+
app_version=None, # app version string
|
|
100
|
+
lang_code=None, # IETF language tag, e.g. "en"
|
|
101
|
+
system_lang_code=None, # system locale tag
|
|
102
|
+
lang_pack=None, # language pack name
|
|
103
|
+
|
|
104
|
+
# Experimental
|
|
105
|
+
allow_missing_channel_hash=False, # skip access hash requirement for channels
|
|
106
|
+
auto_resolve_peers=False, # resolve unknown peers automatically
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`proxy` supports two formats:
|
|
111
|
+
- SOCKS5: `"socks5://host:port"`
|
|
112
|
+
- MTProxy: `"https://t.me/proxy?server=...&port=...&secret=..."`
|
|
113
|
+
|
|
62
114
|
|
|
63
115
|
## Event Handlers
|
|
64
116
|
|
|
@@ -90,8 +142,8 @@ Handler signature: `async def handler(client, update):`
|
|
|
90
142
|
|
|
91
143
|
## Filters
|
|
92
144
|
|
|
93
|
-
Import:
|
|
94
|
-
```
|
|
145
|
+
Import:
|
|
146
|
+
```python
|
|
95
147
|
from ferogram import filters
|
|
96
148
|
```
|
|
97
149
|
|
|
@@ -185,9 +237,11 @@ filters.not_(f1)
|
|
|
185
237
|
## Messaging
|
|
186
238
|
|
|
187
239
|
```python
|
|
188
|
-
await client.send_message(peer, text, parse_mode=None)
|
|
240
|
+
await client.send_message(peer, text, parse_mode=None, reply_markup=None)
|
|
189
241
|
# parse_mode: None (plain) | "html" | "markdown"
|
|
190
|
-
#
|
|
242
|
+
# reply_markup: InlineKeyboard, ReplyKeyboard, RemoveKeyboard, or ForceReply
|
|
243
|
+
#
|
|
244
|
+
# "markdown" uses MarkdownV2 format since ferogram 0.3.9.
|
|
191
245
|
# __text__ = Underline (was Italic in V1)
|
|
192
246
|
# ~text~ = Strike (was ~~text~~ in V1)
|
|
193
247
|
# > text = Blockquote (new)
|
|
@@ -208,6 +262,7 @@ await client.pin_message(peer, message_id)
|
|
|
208
262
|
await client.unpin_message(peer, message_id)
|
|
209
263
|
await client.unpin_all_messages(peer)
|
|
210
264
|
await client.get_messages_by_id(peer, [id1, id2])
|
|
265
|
+
await client.get_message(peer, msg_id) # -> Message | None (single fetch)
|
|
211
266
|
await client.get_message_history(peer, limit=100, offset_id=0)
|
|
212
267
|
await client.get_pinned_message(peer) # -> Message | None
|
|
213
268
|
await client.get_reply_to_message(peer, msg_id) # -> Message | None
|
|
@@ -217,12 +272,14 @@ await client.send_reaction(peer, message_id, emoji)
|
|
|
217
272
|
await client.read_reactions(peer)
|
|
218
273
|
await client.clear_recent_reactions()
|
|
219
274
|
await client.get_reaction_list(peer, msg_id, limit=100) # -> [(peer_id, emoji)]
|
|
220
|
-
await client.delete_reaction(peer, msg_id, participant) #
|
|
275
|
+
await client.delete_reaction(peer, msg_id, participant) # remove a specific user's reaction (admin only)
|
|
276
|
+
async for reaction in client.iter_reaction_users(peer, msg_id, reaction=None):
|
|
277
|
+
... # yields reaction objects
|
|
221
278
|
await client.mark_as_read(peer)
|
|
222
279
|
await client.clear_mentions(peer)
|
|
223
280
|
await client.send_chat_action(peer, "typing") # or ChatAction.TYPING
|
|
224
281
|
await client.send_dice(peer, emoticon="🎲")
|
|
225
|
-
await client.translate_messages(peer, [msg_id], to_lang="en")
|
|
282
|
+
await client.translate_messages(peer, [msg_id], to_lang="en") # -> [str]
|
|
226
283
|
await client.get_web_page_preview(text) # -> url | None
|
|
227
284
|
```
|
|
228
285
|
|
|
@@ -245,6 +302,55 @@ await message.react(emoji)
|
|
|
245
302
|
`is_forwarded`, `post_author`, `view_count`, `reply_count`
|
|
246
303
|
|
|
247
304
|
|
|
305
|
+
## Keyboards
|
|
306
|
+
|
|
307
|
+
Build and attach keyboards to messages.
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
from ferogram import InlineButton, InlineKeyboard
|
|
311
|
+
from ferogram import ReplyButton, ReplyKeyboard
|
|
312
|
+
from ferogram import RemoveKeyboard, ForceReply
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Inline keyboard**
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
kb = InlineKeyboard([
|
|
319
|
+
[InlineButton("Click me", data="btn1"), InlineButton("Other", data="btn2")],
|
|
320
|
+
[InlineButton("Open URL", url="https://example.com")],
|
|
321
|
+
])
|
|
322
|
+
|
|
323
|
+
await client.send_message(peer, "Pick one:", reply_markup=kb)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
`InlineButton` takes `text` (required) and one of `data`, `url`, `switch_inline_query`, or `switch_inline_query_current_chat`.
|
|
327
|
+
|
|
328
|
+
**Reply keyboard**
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
kb = ReplyKeyboard([
|
|
332
|
+
[ReplyButton("Option A"), ReplyButton("Option B")],
|
|
333
|
+
[ReplyButton("Cancel")],
|
|
334
|
+
], resize=True, one_time=True)
|
|
335
|
+
|
|
336
|
+
await client.send_message(peer, "Choose:", reply_markup=kb)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Remove keyboard**
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
await client.send_message(peer, "Done.", reply_markup=RemoveKeyboard())
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Force reply**
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
await client.send_message(peer, "Reply to this:", reply_markup=ForceReply())
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
`reply_markup` works on `send_message`, `send_photo`, `send_document`, `send_file`, and `edit_message`.
|
|
352
|
+
|
|
353
|
+
|
|
248
354
|
## Media
|
|
249
355
|
|
|
250
356
|
```python
|
|
@@ -276,29 +382,178 @@ await client.send_poll(
|
|
|
276
382
|
)
|
|
277
383
|
await client.send_vote(peer, msg_id, options=[b"\x00"])
|
|
278
384
|
await client.get_poll_votes(peer, msg_id, limit=100) # -> [(user_id, option_bytes)]
|
|
279
|
-
await client.get_poll_results(peer, msg_id, poll_hash)
|
|
280
|
-
await client.get_poll_stats(peer, msg_id) # ->
|
|
281
|
-
await client.delete_reaction(peer, msg_id, participant) # report/remove a user's reaction
|
|
385
|
+
await client.get_poll_results(peer, msg_id, poll_hash) # fetch and cache latest results
|
|
386
|
+
await client.get_poll_stats(peer, msg_id) # -> int (interaction count)
|
|
282
387
|
```
|
|
283
388
|
|
|
284
389
|
|
|
285
390
|
## Inline Bots
|
|
286
391
|
|
|
392
|
+
### Answering callback queries
|
|
393
|
+
|
|
287
394
|
```python
|
|
288
395
|
await client.answer_callback_query(query_id, text=None, alert=False)
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Answering inline queries
|
|
289
399
|
|
|
400
|
+
Use `InlineArticle`, `InlinePhoto`, or `InlineDocument` to build results and pass them to `answer_inline_query`.
|
|
401
|
+
|
|
402
|
+
```python
|
|
290
403
|
from ferogram import InlineArticle, InlinePhoto, InlineDocument
|
|
291
404
|
|
|
292
|
-
await client.answer_inline_query(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
405
|
+
await client.answer_inline_query(
|
|
406
|
+
query_id,
|
|
407
|
+
results=[...],
|
|
408
|
+
cache_time=300,
|
|
409
|
+
is_personal=False,
|
|
410
|
+
next_offset=None, # pass a string to enable pagination
|
|
411
|
+
switch_pm=None, # ("Button text", "start_param") to show a "go to PM" button
|
|
412
|
+
)
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**InlineArticle**
|
|
416
|
+
|
|
417
|
+
```python
|
|
418
|
+
InlineArticle(
|
|
419
|
+
id="1",
|
|
420
|
+
title="My Article",
|
|
421
|
+
message_text="Text sent when user picks this result.",
|
|
422
|
+
description=None, # subtitle shown in the result list
|
|
423
|
+
url=None, # URL shown under the title
|
|
424
|
+
thumb_url=None, # thumbnail URL
|
|
425
|
+
reply_markup=None, # InlineKeyboard attached to the sent message
|
|
426
|
+
)
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**InlinePhoto**
|
|
430
|
+
|
|
431
|
+
```python
|
|
432
|
+
InlinePhoto(
|
|
433
|
+
id="2",
|
|
434
|
+
title="A Photo",
|
|
435
|
+
message_text="Caption for the photo.",
|
|
436
|
+
photo_url="https://example.com/photo.jpg", # required, direct image URL
|
|
437
|
+
photo_width=0, # optional dimensions hint
|
|
438
|
+
photo_height=0,
|
|
439
|
+
description=None,
|
|
440
|
+
thumb_url=None,
|
|
441
|
+
mime_type="image/jpeg",
|
|
442
|
+
reply_markup=None,
|
|
443
|
+
)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**InlineDocument**
|
|
447
|
+
|
|
448
|
+
```python
|
|
449
|
+
InlineDocument(
|
|
450
|
+
id="3",
|
|
451
|
+
title="A File",
|
|
452
|
+
message_text="Here is the file.",
|
|
453
|
+
document_url="https://example.com/file.pdf", # required, direct file URL
|
|
454
|
+
mime_type="application/pdf", # required
|
|
455
|
+
description=None,
|
|
456
|
+
thumb_url=None,
|
|
457
|
+
reply_markup=None,
|
|
458
|
+
)
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
**Simple articles shortcut**
|
|
462
|
+
|
|
463
|
+
If you only need plain text articles with no extra fields, there is a lighter helper:
|
|
464
|
+
|
|
465
|
+
```python
|
|
466
|
+
await client.answer_inline_query_articles(
|
|
467
|
+
query_id,
|
|
468
|
+
articles=[
|
|
469
|
+
("id1", "Title One", "Message text one"),
|
|
470
|
+
("id2", "Title Two", "Message text two"),
|
|
471
|
+
],
|
|
472
|
+
cache_time=300,
|
|
473
|
+
is_personal=False,
|
|
474
|
+
next_offset=None,
|
|
475
|
+
)
|
|
476
|
+
```
|
|
297
477
|
|
|
478
|
+
### Editing inline messages
|
|
479
|
+
|
|
480
|
+
After answering an inline query, you can edit the message later using the ID from `InlineSend`.
|
|
481
|
+
|
|
482
|
+
```python
|
|
298
483
|
from ferogram import InlineMessageId
|
|
299
|
-
|
|
484
|
+
|
|
485
|
+
await client.edit_inline_message(
|
|
486
|
+
InlineMessageId(dc_id=2, id_bytes=b"..."),
|
|
487
|
+
"updated text",
|
|
488
|
+
reply_markup=None, # optionally attach or update the keyboard
|
|
489
|
+
)
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
To get the `InlineMessageId` from a send event:
|
|
493
|
+
|
|
494
|
+
```python
|
|
495
|
+
@app.on_inline_send()
|
|
496
|
+
async def handler(client, send):
|
|
497
|
+
# send.user_id int
|
|
498
|
+
# send.query str
|
|
499
|
+
# send.result_id str
|
|
500
|
+
# send.msg_id_bytes bytes | None (raw serialized InputBotInlineMessageId)
|
|
501
|
+
# send.msg_id_dc int | None (DC where the message lives)
|
|
502
|
+
|
|
503
|
+
if send.msg_id_bytes:
|
|
504
|
+
msg_id = InlineMessageId(send.msg_id_dc, bytes(send.msg_id_bytes))
|
|
505
|
+
await client.edit_inline_message(msg_id, "updated!")
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
`msg_id_bytes` and `msg_id_dc` are `None` when the bot did not request inline feedback for this query (i.e. the result was sent without enabling `@BotFather` inline feedback).
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
## Participants
|
|
512
|
+
|
|
513
|
+
These methods work on groups, supergroups, and channels.
|
|
514
|
+
|
|
515
|
+
```python
|
|
516
|
+
await client.get_participants(peer, limit=200)
|
|
517
|
+
# -> list[ChatMember]
|
|
518
|
+
|
|
519
|
+
await client.get_participants_filtered(peer, filter="recent", limit=200)
|
|
520
|
+
# filter: "recent" | "admins" | "kicked" | "banned" | "bots"
|
|
521
|
+
# -> list[ChatMember]
|
|
522
|
+
|
|
523
|
+
await client.kick_participant(peer, user)
|
|
524
|
+
# Removes the user from the chat. They can rejoin if the chat is public or they have an invite link.
|
|
525
|
+
|
|
526
|
+
await client.ban_participant(peer, user)
|
|
527
|
+
# Permanently bans until manually lifted.
|
|
528
|
+
|
|
529
|
+
await client.ban_participant_until(peer, user, until_date)
|
|
530
|
+
# until_date is a unix timestamp. The ban lifts automatically after that time.
|
|
531
|
+
|
|
532
|
+
await client.promote_participant(peer, user, rights=None)
|
|
533
|
+
# rights is a list of permission strings. Pass None to grant all admin rights.
|
|
534
|
+
# Valid strings: "change_info", "post_messages", "edit_messages",
|
|
535
|
+
# "delete_messages", "ban_users", "invite_users",
|
|
536
|
+
# "pin_messages", "add_admins", "manage_call"
|
|
537
|
+
|
|
538
|
+
await client.demote_participant(peer, user)
|
|
539
|
+
# Removes all admin rights. The user stays as a regular member.
|
|
540
|
+
|
|
541
|
+
await client.get_profile_photos(peer, limit=100)
|
|
542
|
+
# -> list of (file_id, access_hash, dc_id) tuples
|
|
543
|
+
|
|
544
|
+
await client.search_peer(query)
|
|
545
|
+
# Search the local peer cache by name or username.
|
|
546
|
+
# -> list[str] of matching peer identifiers
|
|
547
|
+
|
|
548
|
+
client.signal_network_restored()
|
|
549
|
+
# Not async. Call this when you know network is back to trigger an immediate
|
|
550
|
+
# reconnect attempt instead of waiting for the retry timer.
|
|
300
551
|
```
|
|
301
552
|
|
|
553
|
+
### ChatMember fields
|
|
554
|
+
|
|
555
|
+
`user_id`, `first_name`, `last_name`, `username`, `bot`, `status`, `admin_rank`, `full_name`
|
|
556
|
+
|
|
302
557
|
|
|
303
558
|
## Chats & Groups
|
|
304
559
|
|
|
@@ -332,10 +587,6 @@ await client.get_pinned_dialogs(folder_id=0) # 0=main, 1=archive
|
|
|
332
587
|
await client.mark_dialog_read(peer)
|
|
333
588
|
```
|
|
334
589
|
|
|
335
|
-
### ChatMember fields
|
|
336
|
-
|
|
337
|
-
`user_id`, `first_name`, `last_name`, `username`, `bot`, `status`, `admin_rank`, `full_name`
|
|
338
|
-
|
|
339
590
|
|
|
340
591
|
## Forum Topics
|
|
341
592
|
|
|
@@ -355,6 +606,35 @@ await client.all_join_requests(peer, approve=True, link=None)
|
|
|
355
606
|
```
|
|
356
607
|
|
|
357
608
|
|
|
609
|
+
## Invite Links
|
|
610
|
+
|
|
611
|
+
```python
|
|
612
|
+
await client.invite_links(peer) # -> [ExportedChatInvite]
|
|
613
|
+
await client.invite_links(peer, primary_only=True) # -> ExportedChatInvite (primary link)
|
|
614
|
+
await client.invite_links(peer, revoked=True) # -> [ExportedChatInvite] (revoked links)
|
|
615
|
+
|
|
616
|
+
async for link in client.iter_invite_links(peer, revoked=False):
|
|
617
|
+
... # yields ExportedChatInvite objects
|
|
618
|
+
|
|
619
|
+
async for member in client.iter_invite_link_members(peer, link, requested=False):
|
|
620
|
+
... # yields ChatInviteImporter objects
|
|
621
|
+
|
|
622
|
+
await client.edit_invite_link(
|
|
623
|
+
peer, link,
|
|
624
|
+
expire_date=None, # unix timestamp; None = no expiry
|
|
625
|
+
usage_limit=None, # None = unlimited
|
|
626
|
+
request_needed=None, # require admin approval to join
|
|
627
|
+
title=None,
|
|
628
|
+
)
|
|
629
|
+
await client.revoke_invite_link(peer, link) # -> revoked ExportedChatInvite
|
|
630
|
+
await client.delete_invite_link(peer, link) # delete a revoked link permanently
|
|
631
|
+
await client.clear_revoked_invite_links(peer) # delete all revoked links
|
|
632
|
+
|
|
633
|
+
await client.resolve_invite_link(link) # peek without joining -> ChatInvite
|
|
634
|
+
await client.join_invite_link(link) # join and return InputPeer
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
|
|
358
638
|
## Account & Profile
|
|
359
639
|
|
|
360
640
|
```python
|
|
@@ -362,6 +642,10 @@ await client.get_me() # -> User
|
|
|
362
642
|
await client.get_users_by_id([user_id, ...]) # -> [User | None]
|
|
363
643
|
await client.get_user_full(user_id) # -> UserFull
|
|
364
644
|
await client.get_dialogs(limit=100) # -> [Dialog]
|
|
645
|
+
async for dialog in client.iter_dialogs(limit=None):
|
|
646
|
+
... # yields Dialog objects
|
|
647
|
+
async for msg in client.iter_messages(peer, limit=None, offset_id=0):
|
|
648
|
+
... # yields Message objects, newest first
|
|
365
649
|
await client.set_profile(first_name=None, last_name=None, about=None)
|
|
366
650
|
await client.set_username(username)
|
|
367
651
|
await client.set_online()
|
|
@@ -432,7 +716,9 @@ await client.set_privacy(PrivacyKey.PHONE_NUMBER, PrivacyRule.ALLOW_CONTACTS)
|
|
|
432
716
|
## Sessions & Auth
|
|
433
717
|
|
|
434
718
|
```python
|
|
435
|
-
await client.
|
|
719
|
+
await client.is_authorized() # -> bool
|
|
720
|
+
await client.login_bot(token) # sign in as bot after start()
|
|
721
|
+
await client.get_authorizations() # -> [Authorization]
|
|
436
722
|
await client.terminate_session(hash)
|
|
437
723
|
|
|
438
724
|
# QR login
|
|
@@ -455,10 +741,10 @@ await client.open_mini_app(peer, app_type="main", app_value="") # -> MiniAppSe
|
|
|
455
741
|
## Stats
|
|
456
742
|
|
|
457
743
|
```python
|
|
458
|
-
await client.get_broadcast_stats(peer)
|
|
459
|
-
await client.get_megagroup_stats(peer)
|
|
744
|
+
await client.get_broadcast_stats(peer) # -> BroadcastStats
|
|
745
|
+
await client.get_megagroup_stats(peer) # -> MegagroupStats
|
|
460
746
|
await client.get_game_high_scores(peer, msg_id, user_id) # -> [(position, user_id, score)]
|
|
461
|
-
await client.get_poll_stats(peer, msg_id)
|
|
747
|
+
await client.get_poll_stats(peer, msg_id) # -> int (interaction count)
|
|
462
748
|
```
|
|
463
749
|
|
|
464
750
|
|
|
@@ -475,6 +761,15 @@ await client.send_invoice(
|
|
|
475
761
|
```
|
|
476
762
|
|
|
477
763
|
|
|
764
|
+
## Custom Emoji
|
|
765
|
+
|
|
766
|
+
```python
|
|
767
|
+
await client.get_custom_emoji_documents(document_ids=[...])
|
|
768
|
+
# Pass a list of custom emoji document IDs.
|
|
769
|
+
# Returns the subset of IDs that resolved successfully.
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
|
|
478
773
|
## Peer Resolution
|
|
479
774
|
|
|
480
775
|
```python
|
|
@@ -640,4 +935,3 @@ ChatAction.RECORD_ROUND
|
|
|
640
935
|
ChatAction.UPLOAD_ROUND
|
|
641
936
|
ChatAction.CANCEL
|
|
642
937
|
```
|
|
643
|
-
|