tlgr-cli 2.0.1__py3-none-any.whl
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.
- tlgr/__init__.py +3 -0
- tlgr/__main__.py +6 -0
- tlgr/actions/__init__.py +45 -0
- tlgr/actions/forward.py +74 -0
- tlgr/actions/reply.py +32 -0
- tlgr/cli/__init__.py +259 -0
- tlgr/cli/confirm.py +55 -0
- tlgr/cli/errors.py +84 -0
- tlgr/cli/gen.py +690 -0
- tlgr/cli/globals.py +273 -0
- tlgr/cli/introspect.py +170 -0
- tlgr/cli/params.py +189 -0
- tlgr/cli/render.py +418 -0
- tlgr/core/__init__.py +0 -0
- tlgr/core/accounts.py +384 -0
- tlgr/core/config.py +358 -0
- tlgr/core/custom_tl.py +170 -0
- tlgr/core/errors.py +687 -0
- tlgr/core/eventtypes.py +1170 -0
- tlgr/core/identity.py +127 -0
- tlgr/core/launchd.py +122 -0
- tlgr/core/logging.py +194 -0
- tlgr/core/media.py +134 -0
- tlgr/core/output.py +251 -0
- tlgr/core/pagination.py +227 -0
- tlgr/core/paths.py +360 -0
- tlgr/core/peers.py +427 -0
- tlgr/core/process.py +138 -0
- tlgr/core/signing.py +38 -0
- tlgr/core/systemd.py +96 -0
- tlgr/core/telethon_compat.py +295 -0
- tlgr/core/text.py +211 -0
- tlgr/core/timefmt.py +199 -0
- tlgr/core/tl.py +98 -0
- tlgr/daemon/__init__.py +0 -0
- tlgr/daemon/app.py +869 -0
- tlgr/daemon/dispatch.py +446 -0
- tlgr/daemon/events.py +723 -0
- tlgr/daemon/files.py +431 -0
- tlgr/daemon/idle.py +119 -0
- tlgr/daemon/jobs.py +68 -0
- tlgr/daemon/main.py +161 -0
- tlgr/daemon/peercred.py +75 -0
- tlgr/daemon/policy.py +113 -0
- tlgr/daemon/preauth.py +366 -0
- tlgr/daemon/ratelimit.py +391 -0
- tlgr/daemon/server.py +24 -0
- tlgr/daemon/session.py +648 -0
- tlgr/daemon/sessions.py +274 -0
- tlgr/daemon/singleton.py +114 -0
- tlgr/daemon/stream.py +193 -0
- tlgr/daemon/transfers.py +219 -0
- tlgr/daemon/webhook.py +390 -0
- tlgr/data/catalog_index.json +1 -0
- tlgr/data/parity_waivers.toml +90 -0
- tlgr/filters/__init__.py +42 -0
- tlgr/filters/compose.py +121 -0
- tlgr/filters/content.py +85 -0
- tlgr/filters/context.py +114 -0
- tlgr/filters/message.py +161 -0
- tlgr/filters/temporal.py +87 -0
- tlgr/filters/user.py +36 -0
- tlgr/gateway/__init__.py +1 -0
- tlgr/gateway/config.py +161 -0
- tlgr/gateway/engine.py +215 -0
- tlgr/gateway/event.py +22 -0
- tlgr/jobs/__init__.py +0 -0
- tlgr/jobs/base.py +81 -0
- tlgr/jobs/client.py +37 -0
- tlgr/models/__init__.py +1220 -0
- tlgr/models/admin.py +744 -0
- tlgr/models/auth.py +510 -0
- tlgr/models/base.py +81 -0
- tlgr/models/bot.py +576 -0
- tlgr/models/business.py +265 -0
- tlgr/models/call.py +586 -0
- tlgr/models/config.py +101 -0
- tlgr/models/contact.py +481 -0
- tlgr/models/daemon.py +336 -0
- tlgr/models/dialog.py +626 -0
- tlgr/models/envelope.py +68 -0
- tlgr/models/error.py +30 -0
- tlgr/models/event.py +79 -0
- tlgr/models/export.py +66 -0
- tlgr/models/gift.py +275 -0
- tlgr/models/inline.py +84 -0
- tlgr/models/location.py +115 -0
- tlgr/models/media.py +507 -0
- tlgr/models/message.py +584 -0
- tlgr/models/net.py +232 -0
- tlgr/models/notify.py +105 -0
- tlgr/models/page.py +32 -0
- tlgr/models/payment.py +172 -0
- tlgr/models/peer.py +400 -0
- tlgr/models/poll.py +119 -0
- tlgr/models/premium.py +161 -0
- tlgr/models/privacy.py +93 -0
- tlgr/models/profile.py +217 -0
- tlgr/models/reaction.py +160 -0
- tlgr/models/resolve.py +175 -0
- tlgr/models/settings.py +103 -0
- tlgr/models/stars.py +101 -0
- tlgr/models/sticker.py +243 -0
- tlgr/models/story.py +467 -0
- tlgr/models/sync.py +105 -0
- tlgr/models/todo.py +36 -0
- tlgr/models/webapp.py +89 -0
- tlgr/ops/__init__.py +63 -0
- tlgr/ops/_admin.py +313 -0
- tlgr/ops/_auth.py +599 -0
- tlgr/ops/_bots.py +586 -0
- tlgr/ops/_calls.py +535 -0
- tlgr/ops/_common.py +160 -0
- tlgr/ops/_layer.py +46 -0
- tlgr/ops/_media.py +592 -0
- tlgr/ops/_params.py +212 -0
- tlgr/ops/_rights.py +402 -0
- tlgr/ops/_send.py +593 -0
- tlgr/ops/_serialize.py +667 -0
- tlgr/ops/_settings.py +306 -0
- tlgr/ops/_spec.py +167 -0
- tlgr/ops/_story.py +743 -0
- tlgr/ops/account.py +2604 -0
- tlgr/ops/agent.py +937 -0
- tlgr/ops/auth.py +1282 -0
- tlgr/ops/bot.py +4880 -0
- tlgr/ops/business.py +1520 -0
- tlgr/ops/call.py +1610 -0
- tlgr/ops/chat.py +4025 -0
- tlgr/ops/chat_admin.py +929 -0
- tlgr/ops/chat_extra.py +1061 -0
- tlgr/ops/chat_invite.py +716 -0
- tlgr/ops/chat_manage.py +1691 -0
- tlgr/ops/chat_member.py +1357 -0
- tlgr/ops/chat_stats.py +902 -0
- tlgr/ops/chat_topic.py +905 -0
- tlgr/ops/conference.py +791 -0
- tlgr/ops/config.py +1698 -0
- tlgr/ops/contact.py +2330 -0
- tlgr/ops/daemon.py +1397 -0
- tlgr/ops/draft.py +299 -0
- tlgr/ops/emoji.py +343 -0
- tlgr/ops/events.py +1327 -0
- tlgr/ops/export.py +596 -0
- tlgr/ops/folder.py +1322 -0
- tlgr/ops/gif.py +522 -0
- tlgr/ops/gift.py +1546 -0
- tlgr/ops/giveaway.py +541 -0
- tlgr/ops/inline.py +773 -0
- tlgr/ops/job.py +799 -0
- tlgr/ops/location.py +917 -0
- tlgr/ops/media.py +4495 -0
- tlgr/ops/message.py +3769 -0
- tlgr/ops/net.py +536 -0
- tlgr/ops/notify.py +840 -0
- tlgr/ops/passport.py +464 -0
- tlgr/ops/payment.py +907 -0
- tlgr/ops/poll.py +1078 -0
- tlgr/ops/premium.py +488 -0
- tlgr/ops/privacy.py +794 -0
- tlgr/ops/profile.py +1481 -0
- tlgr/ops/proxy.py +750 -0
- tlgr/ops/reaction.py +1475 -0
- tlgr/ops/resolve.py +1140 -0
- tlgr/ops/search.py +521 -0
- tlgr/ops/settings.py +1066 -0
- tlgr/ops/stars.py +594 -0
- tlgr/ops/sticker.py +1602 -0
- tlgr/ops/story.py +3216 -0
- tlgr/ops/sync.py +788 -0
- tlgr/ops/todo.py +514 -0
- tlgr/ops/user.py +1406 -0
- tlgr/ops/vc.py +2351 -0
- tlgr/ops/webapp.py +717 -0
- tlgr/ops/webhook.py +418 -0
- tlgr/parity.py +386 -0
- tlgr/processors/__init__.py +125 -0
- tlgr/processors/regex.py +26 -0
- tlgr/processors/text.py +56 -0
- tlgr/registry.py +519 -0
- tlgr/schema.py +173 -0
- tlgr/transport/__init__.py +30 -0
- tlgr/transport/autostart.py +293 -0
- tlgr/transport/client.py +805 -0
- tlgr/transport/ndjson.py +44 -0
- tlgr/version.py +31 -0
- tlgr_cli-2.0.1.dist-info/METADATA +957 -0
- tlgr_cli-2.0.1.dist-info/RECORD +192 -0
- tlgr_cli-2.0.1.dist-info/WHEEL +5 -0
- tlgr_cli-2.0.1.dist-info/entry_points.txt +2 -0
- tlgr_cli-2.0.1.dist-info/licenses/LICENSE +21 -0
- tlgr_cli-2.0.1.dist-info/top_level.txt +1 -0
tlgr/models/privacy.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Privacy rules, the global privacy switches, and paid-message revenue.
|
|
2
|
+
|
|
3
|
+
`account.setPrivacy` **replaces** the whole ordered rule vector, and
|
|
4
|
+
`account.setGlobalPrivacySettings` replaces the whole constructor. Both are
|
|
5
|
+
therefore read-modify-write operations, and both need a model that survives
|
|
6
|
+
the round trip without losing anything:
|
|
7
|
+
|
|
8
|
+
* `PrivacySettings` splits the vector into the four exception lists a human
|
|
9
|
+
edits *and* keeps `raw_rules` — the constructors in server order — so a
|
|
10
|
+
rule tlgr does not recognise is still sent back unchanged.
|
|
11
|
+
* `GlobalPrivacy` names every field of the constructor, so patching one and
|
|
12
|
+
writing the rest back cannot silently clear a switch nobody mentioned.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from tlgr.models.base import Model
|
|
18
|
+
from tlgr.models.peer import Peer
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"GlobalPrivacy",
|
|
22
|
+
"PaidMessageRevenue",
|
|
23
|
+
"PrivacyExceptions",
|
|
24
|
+
"PrivacyRule",
|
|
25
|
+
"PrivacySettings",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PrivacyRule(Model):
|
|
30
|
+
"""One `privacyValue*` constructor, in tlgr's vocabulary."""
|
|
31
|
+
|
|
32
|
+
#: allow | disallow
|
|
33
|
+
action: str = "allow"
|
|
34
|
+
#: all | contacts | close-friends | premium | bots | users | chats
|
|
35
|
+
scope: str = "all"
|
|
36
|
+
ids: list[int] = []
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class PrivacyExceptions(Model):
|
|
40
|
+
"""The four lists the GUI calls "Always allow" / "Never allow"."""
|
|
41
|
+
|
|
42
|
+
allow_users: list[int] = []
|
|
43
|
+
deny_users: list[int] = []
|
|
44
|
+
allow_chats: list[int] = []
|
|
45
|
+
deny_chats: list[int] = []
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PrivacySettings(Model):
|
|
49
|
+
"""One privacy key, read or written.
|
|
50
|
+
|
|
51
|
+
`base` is the headline the GUI shows; the exception lists are what it
|
|
52
|
+
puts under it. `raw_rules` is the server's own ordered vector, kept so a
|
|
53
|
+
write can reproduce it exactly.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
key: str
|
|
57
|
+
#: everybody | contacts | close-friends | premium | bots | nobody. No
|
|
58
|
+
#: default: it is the headline, and `omit_defaults` would hide the most
|
|
59
|
+
#: restrictive answer exactly when a caller most wants to see it.
|
|
60
|
+
base: str
|
|
61
|
+
allow_users: list[int] = []
|
|
62
|
+
deny_users: list[int] = []
|
|
63
|
+
allow_chats: list[int] = []
|
|
64
|
+
deny_chats: list[int] = []
|
|
65
|
+
raw_rules: list[PrivacyRule] = []
|
|
66
|
+
#: Resolved names for the exception ids, when `--resolve` was given.
|
|
67
|
+
peers: list[Peer] = []
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class GlobalPrivacy(Model):
|
|
71
|
+
"""`globalPrivacySettings`, every field named.
|
|
72
|
+
|
|
73
|
+
Nothing here defaults to a value the server might disagree with: each
|
|
74
|
+
flag is a tri-state so "the server did not report it" stays different
|
|
75
|
+
from "off", which is what makes the read-modify-write safe.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
hide_read_marks: bool | None = None
|
|
79
|
+
archive_and_mute_new_noncontact_peers: bool | None = None
|
|
80
|
+
new_noncontact_peers_require_premium: bool | None = None
|
|
81
|
+
noncontact_peers_paid_stars: int | None = None
|
|
82
|
+
keep_archived_unmuted: bool | None = None
|
|
83
|
+
keep_archived_folders: bool | None = None
|
|
84
|
+
display_gifts_button: bool | None = None
|
|
85
|
+
#: unlimited | limited | unique | premium | from-channels
|
|
86
|
+
disallowed_gifts: list[str] = []
|
|
87
|
+
changed: list[str] = []
|
|
88
|
+
already: bool = False
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class PaidMessageRevenue(Model):
|
|
92
|
+
user_id: int
|
|
93
|
+
stars_amount: int = 0
|
tlgr/models/profile.py
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""My own profile — the Settings ▸ Edit Profile screen, as data.
|
|
2
|
+
|
|
3
|
+
Everything here describes *this* account rather than somebody else's: the
|
|
4
|
+
name and bio the world sees, the usernames (including the Fragment
|
|
5
|
+
collectibles), the avatar history, the accent colours, the emoji status and
|
|
6
|
+
the presence switch.
|
|
7
|
+
|
|
8
|
+
Two shapes are deliberate.
|
|
9
|
+
|
|
10
|
+
* **`ProfileFull` is one object, not a union of three RPCs.** `users.getUsers`
|
|
11
|
+
answers the name, `users.getFullUser` the bio, birthday, personal channel
|
|
12
|
+
and gift counters. v1 fetched only the first and hard-coded `bio` to `""`,
|
|
13
|
+
which is a wrong answer dressed as a real one. One model, both calls.
|
|
14
|
+
* **A username is a row, not a string.** A collectible bought on Fragment can
|
|
15
|
+
be active or parked, and only the *first* active one is the main handle;
|
|
16
|
+
flattening the vector to `username` is how a script deactivates the wrong
|
|
17
|
+
name.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
from tlgr.models.base import Model
|
|
25
|
+
from tlgr.models.peer import Peer
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"AdminedChannel",
|
|
29
|
+
"ColorPalette",
|
|
30
|
+
"ColorSet",
|
|
31
|
+
"EmojiStatusItem",
|
|
32
|
+
"EmojiStatusSet",
|
|
33
|
+
"PhotosDeleted",
|
|
34
|
+
"PresenceSet",
|
|
35
|
+
"ProfileFull",
|
|
36
|
+
"ProfileLink",
|
|
37
|
+
"ProfilePhotoSet",
|
|
38
|
+
"ProfileUpdated",
|
|
39
|
+
"ProfileUsername",
|
|
40
|
+
"UsernameSet",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ProfileUsername(Model):
|
|
45
|
+
"""One entry of `user.usernames`.
|
|
46
|
+
|
|
47
|
+
`main` is derived rather than reported: the server marks the basic
|
|
48
|
+
username with `editable`, and the first *active* entry is what a link
|
|
49
|
+
resolves to. Both facts matter and neither is the other.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
username: str
|
|
53
|
+
active: bool = True
|
|
54
|
+
editable: bool = False
|
|
55
|
+
main: bool = False
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ProfileFull(Model):
|
|
59
|
+
"""My profile as the Edit Profile screen shows it."""
|
|
60
|
+
|
|
61
|
+
id: int = 0
|
|
62
|
+
first_name: str = ""
|
|
63
|
+
last_name: str = ""
|
|
64
|
+
username: str | None = None
|
|
65
|
+
usernames: list[ProfileUsername] = []
|
|
66
|
+
phone: str | None = None
|
|
67
|
+
premium: bool = False
|
|
68
|
+
bot: bool = False
|
|
69
|
+
#: Only present with `--full`; `""` means "fetched and empty", `None`
|
|
70
|
+
#: means "not fetched", which v1 could not tell apart.
|
|
71
|
+
bio: str | None = None
|
|
72
|
+
birthday: str | None = None
|
|
73
|
+
personal_channel_id: int | None = None
|
|
74
|
+
personal_channel: Peer | None = None
|
|
75
|
+
emoji_status: int | None = None
|
|
76
|
+
emoji_status_collectible_id: int | None = None
|
|
77
|
+
emoji_status_until: str | None = None
|
|
78
|
+
color: int | None = None
|
|
79
|
+
color_collectible_id: int | None = None
|
|
80
|
+
background_emoji_id: int | None = None
|
|
81
|
+
profile_color: int | None = None
|
|
82
|
+
profile_background_emoji_id: int | None = None
|
|
83
|
+
#: Which tab the profile page opens on (`stargifts`, `posts`, …).
|
|
84
|
+
main_tab: str | None = None
|
|
85
|
+
stargifts_count: int | None = None
|
|
86
|
+
stars_rating: int | None = None
|
|
87
|
+
ttl_period: int | None = None
|
|
88
|
+
sponsored_enabled: bool | None = None
|
|
89
|
+
#: Gift categories this account refuses, from `disallowed_gifts`.
|
|
90
|
+
disallowed_gifts: list[str] = []
|
|
91
|
+
photo_id: int | None = None
|
|
92
|
+
fallback_photo_id: int | None = None
|
|
93
|
+
contacts_count: int | None = None
|
|
94
|
+
common_chats_count: int | None = None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ProfileUpdated(Model):
|
|
98
|
+
"""What `profile update` actually changed, field by field.
|
|
99
|
+
|
|
100
|
+
Only the fields the caller named appear, because the command spans three
|
|
101
|
+
RPCs and "I asked for a birthday and got a name back" is a report nobody
|
|
102
|
+
can act on.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
first_name: str | None = None
|
|
106
|
+
last_name: str | None = None
|
|
107
|
+
bio: str | None = None
|
|
108
|
+
birthday: str | None = None
|
|
109
|
+
personal_channel_id: int | None = None
|
|
110
|
+
photo_id: int | None = None
|
|
111
|
+
changed: list[str] = []
|
|
112
|
+
already: bool = False
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class UsernameSet(Model):
|
|
116
|
+
"""`profile username set`, in all five of its moods."""
|
|
117
|
+
|
|
118
|
+
username: str | None = None
|
|
119
|
+
active: bool | None = None
|
|
120
|
+
#: Only for `--check`: whether the name may be taken right now.
|
|
121
|
+
available: bool | None = None
|
|
122
|
+
#: Set when the server says `USERNAME_PURCHASE_AVAILABLE`: the name is
|
|
123
|
+
#: free only on Fragment, which is a different answer from "taken".
|
|
124
|
+
purchasable: bool = False
|
|
125
|
+
usernames: list[ProfileUsername] = []
|
|
126
|
+
already: bool = False
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class ColorPalette(Model):
|
|
130
|
+
"""One entry of `help.getPeerColors` / `getPeerProfileColors`."""
|
|
131
|
+
|
|
132
|
+
color_id: int
|
|
133
|
+
colors: list[str] = []
|
|
134
|
+
dark_colors: list[str] = []
|
|
135
|
+
min_level: int = 0
|
|
136
|
+
hidden: bool = False
|
|
137
|
+
channel_min_level: int | None = None
|
|
138
|
+
group_min_level: int | None = None
|
|
139
|
+
#: True for palettes 0-6, whose colours every client hard-codes.
|
|
140
|
+
builtin: bool = False
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class ColorSet(Model):
|
|
144
|
+
"""`profile color set`: the palette now in force."""
|
|
145
|
+
|
|
146
|
+
color: int | None = None
|
|
147
|
+
collectible_id: int | None = None
|
|
148
|
+
background_emoji_id: int | None = None
|
|
149
|
+
for_profile: bool = False
|
|
150
|
+
already: bool = False
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class EmojiStatusItem(Model):
|
|
154
|
+
"""A wearable emoji status, from any of the four suggestion lists."""
|
|
155
|
+
|
|
156
|
+
document_id: int = 0
|
|
157
|
+
collectible_id: int | None = None
|
|
158
|
+
title: str | None = None
|
|
159
|
+
slug: str | None = None
|
|
160
|
+
group: str = ""
|
|
161
|
+
until: str | None = None
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class EmojiStatusSet(Model):
|
|
165
|
+
document_id: int | None = None
|
|
166
|
+
collectible_id: int | None = None
|
|
167
|
+
until: str | None = None
|
|
168
|
+
until_unix: int | None = None
|
|
169
|
+
cleared: bool = False
|
|
170
|
+
already: bool = False
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class PresenceSet(Model):
|
|
174
|
+
"""`profile presence set`. `online` is what was *reported*, not measured."""
|
|
175
|
+
|
|
176
|
+
online: bool
|
|
177
|
+
already: bool = False
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class ProfilePhotoSet(Model):
|
|
181
|
+
photo_id: int | None = None
|
|
182
|
+
is_video: bool = False
|
|
183
|
+
fallback: bool = False
|
|
184
|
+
#: Set when the avatar was built server-side from a custom emoji.
|
|
185
|
+
emoji_markup: bool = False
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class PhotosDeleted(Model):
|
|
189
|
+
deleted: int = 0
|
|
190
|
+
photo_ids: list[int] = []
|
|
191
|
+
already: bool = False
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class ProfileLink(Model):
|
|
195
|
+
"""`profile link`: the public handle, and what Fragment knows about it."""
|
|
196
|
+
|
|
197
|
+
#: No default: `omit_defaults` would drop the reassuring answer and
|
|
198
|
+
#: leave a caller unable to tell "public" from "not reported".
|
|
199
|
+
resolvable_by_strangers: bool
|
|
200
|
+
link: str = ""
|
|
201
|
+
username: str | None = None
|
|
202
|
+
user_id: int | None = None
|
|
203
|
+
#: A unicode-block QR, when `--qr` was given.
|
|
204
|
+
qr: str | None = None
|
|
205
|
+
qr_path: str | None = None
|
|
206
|
+
#: `fragment.getCollectibleInfo`, when `--collectible` was given.
|
|
207
|
+
collectible: dict[str, Any] | None = None
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class AdminedChannel(Model):
|
|
211
|
+
"""A public channel eligible to be shown on the profile."""
|
|
212
|
+
|
|
213
|
+
id: int
|
|
214
|
+
title: str = ""
|
|
215
|
+
username: str | None = None
|
|
216
|
+
participants_count: int | None = None
|
|
217
|
+
current: bool = False
|
tlgr/models/reaction.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Reactions: what is on a message, who put it there, and what a chat allows.
|
|
2
|
+
|
|
3
|
+
One spelling for a reaction across the whole group: a unicode emoji is itself
|
|
4
|
+
(`"👍"`) and a custom (Premium) emoji is `"custom:<document_id>"`. The pair
|
|
5
|
+
`(emoji, custom)` is accepted on input and the same string comes back on
|
|
6
|
+
output, so a reaction read from `reaction list` can be handed straight back to
|
|
7
|
+
`reaction remove` without the caller knowing which kind it was.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Literal
|
|
13
|
+
|
|
14
|
+
from tlgr.models.base import Model
|
|
15
|
+
from tlgr.models.message import ReactionSummary
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"AvailableReaction",
|
|
19
|
+
"ChatReactions",
|
|
20
|
+
"MessageReactionState",
|
|
21
|
+
"PaidReactionResult",
|
|
22
|
+
"ReactionPrivacy",
|
|
23
|
+
"ReactionPurge",
|
|
24
|
+
"ReactionReport",
|
|
25
|
+
"ReactionResult",
|
|
26
|
+
"ReactionTag",
|
|
27
|
+
"ReactionUser",
|
|
28
|
+
"TopReactor",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ReactionResult(Model):
|
|
33
|
+
"""What `reaction add` / `reaction remove` did.
|
|
34
|
+
|
|
35
|
+
`emoji` and `reacted` are v1's `message react` keys and stay spelled that
|
|
36
|
+
way; `mine` is the full set my account now holds, because `sendReaction`
|
|
37
|
+
takes the whole desired state and a caller that wants to add a second
|
|
38
|
+
reaction has to know what the first one was.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
chat_id: int
|
|
42
|
+
msg_id: int
|
|
43
|
+
emoji: str = ""
|
|
44
|
+
reacted: bool = False
|
|
45
|
+
already: bool = False
|
|
46
|
+
mine: list[str] = []
|
|
47
|
+
reactions: ReactionSummary | None = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class TopReactor(Model):
|
|
51
|
+
"""A row of the Star-reaction leaderboard on a channel post."""
|
|
52
|
+
|
|
53
|
+
user_id: int | None = None
|
|
54
|
+
stars: int = 0
|
|
55
|
+
anonymous: bool = False
|
|
56
|
+
mine: bool = False
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MessageReactionState(Model):
|
|
60
|
+
"""The reaction state of one message, refreshed from the server."""
|
|
61
|
+
|
|
62
|
+
chat_id: int = 0
|
|
63
|
+
msg_id: int = 0
|
|
64
|
+
reactions: ReactionSummary | None = None
|
|
65
|
+
can_see_list: bool = False
|
|
66
|
+
as_tags: bool = False
|
|
67
|
+
top_reactors: list[TopReactor] = []
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ReactionUser(Model):
|
|
71
|
+
"""Who reacted, with what, and when."""
|
|
72
|
+
|
|
73
|
+
user_id: int
|
|
74
|
+
reaction: str = ""
|
|
75
|
+
date: str | None = None
|
|
76
|
+
date_unix: int | None = None
|
|
77
|
+
big: bool = False
|
|
78
|
+
unread: bool = False
|
|
79
|
+
mine: bool = False
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class AvailableReaction(Model):
|
|
83
|
+
"""One entry of the reaction catalogue.
|
|
84
|
+
|
|
85
|
+
`source` says which list it came from, because the standard catalogue,
|
|
86
|
+
the featured list and my own recent reactions are three different
|
|
87
|
+
questions with three different endpoints and the same row shape.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
emoticon: str
|
|
91
|
+
source: Literal["available", "top", "recent"]
|
|
92
|
+
title: str = ""
|
|
93
|
+
premium: bool = False
|
|
94
|
+
inactive: bool = False
|
|
95
|
+
static_icon_id: int | None = None
|
|
96
|
+
select_animation_id: int | None = None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class ChatReactions(Model):
|
|
100
|
+
"""What a chat (or one message in it) allows.
|
|
101
|
+
|
|
102
|
+
`mode` is the `chatReactions*` variant flattened to a word, because
|
|
103
|
+
`setChatAvailableReactions` demands the whole value on every write: a
|
|
104
|
+
caller changing only `reactions_limit` still has to resend the mode.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
mode: Literal["all", "some", "none"]
|
|
108
|
+
chat_id: int = 0
|
|
109
|
+
msg_id: int | None = None
|
|
110
|
+
reactions: list[str] = []
|
|
111
|
+
allow_custom: bool = False
|
|
112
|
+
reactions_limit: int | None = None
|
|
113
|
+
paid_enabled: bool | None = None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class ReactionTag(Model):
|
|
117
|
+
"""A Saved Messages reaction tag, and the name I gave it."""
|
|
118
|
+
|
|
119
|
+
reaction: str
|
|
120
|
+
title: str | None = None
|
|
121
|
+
count: int = 0
|
|
122
|
+
suggested: bool = False
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class ReactionPrivacy(Model):
|
|
126
|
+
"""How my paid reactions are attributed."""
|
|
127
|
+
|
|
128
|
+
privacy: Literal["default", "anonymous", "peer"]
|
|
129
|
+
peer_id: int | None = None
|
|
130
|
+
msg_id: int | None = None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class PaidReactionResult(Model):
|
|
134
|
+
"""A Star reaction that was actually paid for."""
|
|
135
|
+
|
|
136
|
+
chat_id: int
|
|
137
|
+
msg_id: int
|
|
138
|
+
stars_sent: int = 0
|
|
139
|
+
privacy: Literal["default", "anonymous", "peer"] = "default"
|
|
140
|
+
top_reactors: list[TopReactor] = []
|
|
141
|
+
#: `reaction pay --senders`: the peers I may pay as, listed without paying.
|
|
142
|
+
senders: list[int] = []
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class ReactionPurge(Model):
|
|
146
|
+
"""A moderator's removal of somebody else's reactions."""
|
|
147
|
+
|
|
148
|
+
chat_id: int
|
|
149
|
+
user_id: int
|
|
150
|
+
scope: Literal["message", "chat"]
|
|
151
|
+
msg_id: int | None = None
|
|
152
|
+
deleted: bool = False
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class ReactionReport(Model):
|
|
156
|
+
ok: bool = False
|
|
157
|
+
banned: bool = False
|
|
158
|
+
chat_id: int = 0
|
|
159
|
+
msg_id: int = 0
|
|
160
|
+
user_id: int = 0
|
tlgr/models/resolve.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""Resolution results: what a reference, a link or a cache entry turns into.
|
|
2
|
+
|
|
3
|
+
`resolve` is the one group whose whole job is to be honest about *how* an
|
|
4
|
+
answer was reached, so every shape here carries provenance:
|
|
5
|
+
|
|
6
|
+
* `ResolvedRef.source` says which strategy answered (cache, username, phone,
|
|
7
|
+
dialog scan, arithmetic on a `t.me/c/` link).
|
|
8
|
+
* `ResolvedPhone.reason` exists because `PHONE_NOT_OCCUPIED` is genuinely
|
|
9
|
+
ambiguous — no account, or an owner who refuses phone lookups — and the op
|
|
10
|
+
exits 13 rather than claiming "not found".
|
|
11
|
+
* `ResolvedLink.delegated_to` names the command that would *act* on a link.
|
|
12
|
+
Resolution never joins, starts, installs, boosts or redeems anything; it
|
|
13
|
+
says what the link is and which verb would.
|
|
14
|
+
|
|
15
|
+
No access hash is ever emitted, only `access_hash_cached`.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Any, Literal
|
|
21
|
+
|
|
22
|
+
from tlgr.models.base import Model
|
|
23
|
+
from tlgr.models.peer import Peer
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"CachedPeerRow",
|
|
27
|
+
"LinkKind",
|
|
28
|
+
"ResolvedLink",
|
|
29
|
+
"ResolvedPhone",
|
|
30
|
+
"ResolvedRef",
|
|
31
|
+
"ResolvedUsername",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
#: Every shape a t.me / tg:// reference can take. `unknown` is a real answer:
|
|
35
|
+
#: Telegram adds deep links faster than any client learns them, and reporting
|
|
36
|
+
#: `unknown` with the raw path beats guessing wrong.
|
|
37
|
+
LinkKind = Literal[
|
|
38
|
+
"public-username",
|
|
39
|
+
"phone",
|
|
40
|
+
"invite",
|
|
41
|
+
"chatlist-invite",
|
|
42
|
+
"message",
|
|
43
|
+
"private-post",
|
|
44
|
+
"story",
|
|
45
|
+
"bot-start",
|
|
46
|
+
"bot-startgroup",
|
|
47
|
+
"bot-startchannel",
|
|
48
|
+
"webapp",
|
|
49
|
+
"business-chat-link",
|
|
50
|
+
"contact-token",
|
|
51
|
+
"proxy",
|
|
52
|
+
"boost",
|
|
53
|
+
"giftcode",
|
|
54
|
+
"unique-gift",
|
|
55
|
+
"stars-topup",
|
|
56
|
+
"wallpaper",
|
|
57
|
+
"theme",
|
|
58
|
+
"stickerset",
|
|
59
|
+
"emojiset",
|
|
60
|
+
"share-url",
|
|
61
|
+
"settings-section",
|
|
62
|
+
"contacts-section",
|
|
63
|
+
"login-code",
|
|
64
|
+
"confirm-phone",
|
|
65
|
+
"invoice",
|
|
66
|
+
"premium-offer",
|
|
67
|
+
"folder",
|
|
68
|
+
"unknown",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ResolvedRef(Model, omit_defaults=False):
|
|
73
|
+
"""One `resolve peer` answer, with the strategy that produced it."""
|
|
74
|
+
|
|
75
|
+
ref: str = ""
|
|
76
|
+
kind: str = ""
|
|
77
|
+
id: int | None = None
|
|
78
|
+
marked_id: int | None = None
|
|
79
|
+
botapi_id: int | None = None
|
|
80
|
+
type: str = ""
|
|
81
|
+
title: str = ""
|
|
82
|
+
username: str | None = None
|
|
83
|
+
access_hash_cached: bool = False
|
|
84
|
+
min: bool = False
|
|
85
|
+
source: str = ""
|
|
86
|
+
resolved: bool = False
|
|
87
|
+
reason: str | None = None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ResolvedUsername(Model, omit_defaults=False):
|
|
91
|
+
kind: str = ""
|
|
92
|
+
peer: Peer | None = None
|
|
93
|
+
username: str = ""
|
|
94
|
+
access_hash_cached: bool = False
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ResolvedPhone(Model, omit_defaults=False):
|
|
98
|
+
"""A phone lookup. `resolved=false` with a `reason` is exit 13, not 5."""
|
|
99
|
+
|
|
100
|
+
phone: str = ""
|
|
101
|
+
e164: str = ""
|
|
102
|
+
country: str | None = None
|
|
103
|
+
prefix: str | None = None
|
|
104
|
+
pattern: str | None = None
|
|
105
|
+
resolved: bool = False
|
|
106
|
+
peer: Peer | None = None
|
|
107
|
+
reason: str | None = None
|
|
108
|
+
countries: list[dict[str, Any]] = []
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class ResolvedLink(Model):
|
|
112
|
+
"""A t.me / tg:// link, classified and (optionally) read.
|
|
113
|
+
|
|
114
|
+
One discriminated shape rather than one command per link type: a human
|
|
115
|
+
pasting a link does not know which of twenty kinds it is, and that is
|
|
116
|
+
precisely the question.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
kind: LinkKind
|
|
120
|
+
raw_url: str = ""
|
|
121
|
+
scheme: str = ""
|
|
122
|
+
peer: Peer | None = None
|
|
123
|
+
username: str | None = None
|
|
124
|
+
phone: str | None = None
|
|
125
|
+
invite_hash: str | None = None
|
|
126
|
+
chatlist_slug: str | None = None
|
|
127
|
+
msg_id: int | None = None
|
|
128
|
+
thread_id: int | None = None
|
|
129
|
+
comment_id: int | None = None
|
|
130
|
+
story_id: int | None = None
|
|
131
|
+
bot: str | None = None
|
|
132
|
+
start_param: str | None = None
|
|
133
|
+
start_target: str | None = None
|
|
134
|
+
boost: bool | None = None
|
|
135
|
+
gift: str | None = None
|
|
136
|
+
stars: int | None = None
|
|
137
|
+
proxy: dict[str, Any] | None = None
|
|
138
|
+
theme: str | None = None
|
|
139
|
+
wallpaper: str | None = None
|
|
140
|
+
stickerset: str | None = None
|
|
141
|
+
share: dict[str, Any] | None = None
|
|
142
|
+
contact_token: str | None = None
|
|
143
|
+
section: str | None = None
|
|
144
|
+
deeplink_info: str | None = None
|
|
145
|
+
title: str | None = None
|
|
146
|
+
#: Set only with `--open`: the follow-up read for the classified kind.
|
|
147
|
+
opened: dict[str, Any] | None = None
|
|
148
|
+
requires_action: bool = False
|
|
149
|
+
#: The command that would act on this link. Naming it is the alternative
|
|
150
|
+
#: to acting: joining, starting a bot or redeeming a gift are separate,
|
|
151
|
+
#: confirmed verbs in their own groups.
|
|
152
|
+
delegated_to: str | None = None
|
|
153
|
+
draft_saved: bool = False
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class CachedPeerRow(Model, omit_defaults=False):
|
|
157
|
+
"""One entry of the per-account resolver cache.
|
|
158
|
+
|
|
159
|
+
`min_context` is the `(chat, message)` where a `min` user was seen —
|
|
160
|
+
Telethon stores none, and without it a stranger who posted in a channel
|
|
161
|
+
is unaddressable.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
id: int = 0
|
|
165
|
+
marked_id: int = 0
|
|
166
|
+
type: str = ""
|
|
167
|
+
username: str | None = None
|
|
168
|
+
phone: str | None = None
|
|
169
|
+
access_hash_cached: bool = False
|
|
170
|
+
min: bool = False
|
|
171
|
+
min_context: str | None = None
|
|
172
|
+
seen_at: str | None = None
|
|
173
|
+
seen_at_unix: int | None = None
|
|
174
|
+
refreshed: bool = False
|
|
175
|
+
purged: bool = False
|