toDus-API 1.3.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.
Files changed (35) hide show
  1. todus_api-1.3.3/CHANGELOG.md +61 -0
  2. todus_api-1.3.3/LICENSE +21 -0
  3. todus_api-1.3.3/MANIFEST.in +4 -0
  4. todus_api-1.3.3/PKG-INFO +299 -0
  5. todus_api-1.3.3/README.md +268 -0
  6. todus_api-1.3.3/pyproject.toml +56 -0
  7. todus_api-1.3.3/setup.cfg +4 -0
  8. todus_api-1.3.3/tests/test_proxy.py +65 -0
  9. todus_api-1.3.3/tests/test_stanzas.py +170 -0
  10. todus_api-1.3.3/tests/test_types.py +73 -0
  11. todus_api-1.3.3/tests/test_util.py +175 -0
  12. todus_api-1.3.3/toDus_API.egg-info/PKG-INFO +299 -0
  13. todus_api-1.3.3/toDus_API.egg-info/SOURCES.txt +33 -0
  14. todus_api-1.3.3/toDus_API.egg-info/dependency_links.txt +1 -0
  15. todus_api-1.3.3/toDus_API.egg-info/requires.txt +7 -0
  16. todus_api-1.3.3/toDus_API.egg-info/top_level.txt +1 -0
  17. todus_api-1.3.3/todus/__init__.py +52 -0
  18. todus_api-1.3.3/todus/client/__init__.py +277 -0
  19. todus_api-1.3.3/todus/client/auth.py +89 -0
  20. todus_api-1.3.3/todus/client/base.py +183 -0
  21. todus_api-1.3.3/todus/client/file.py +190 -0
  22. todus_api-1.3.3/todus/client/message.py +202 -0
  23. todus_api-1.3.3/todus/client/profile.py +56 -0
  24. todus_api-1.3.3/todus/constants.py +10 -0
  25. todus_api-1.3.3/todus/errors.py +41 -0
  26. todus_api-1.3.3/todus/group.py +370 -0
  27. todus_api-1.3.3/todus/parser.py +415 -0
  28. todus_api-1.3.3/todus/stanza.py +54 -0
  29. todus_api-1.3.3/todus/stanzas/__init__.py +1 -0
  30. todus_api-1.3.3/todus/stanzas/group.py +175 -0
  31. todus_api-1.3.3/todus/stanzas/presence.py +37 -0
  32. todus_api-1.3.3/todus/stanzas/private.py +203 -0
  33. todus_api-1.3.3/todus/stanzas/utils.py +122 -0
  34. todus_api-1.3.3/todus/types.py +54 -0
  35. todus_api-1.3.3/todus/util.py +177 -0
@@ -0,0 +1,61 @@
1
+ # Changelog
2
+
3
+ Todos los cambios notables en este proyecto se documentan en este archivo.
4
+
5
+ El formato está basado en [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/),
6
+ y este proyecto sigue [Semantic Versioning](https://semver.org/lang/es/).
7
+
8
+ ## [1.3.0] - 2026-06-19
9
+
10
+ ### Added
11
+ - Soporte completo para grupos MUC Light (`GroupClient`)
12
+ - Roles de grupo (`GroupRole`) y eventos de grupo (`GroupEvent`)
13
+ - Auto-detección de destino privado/grupo en `ToDusClient2`
14
+ - Envío de mensajes de ubicación (`send_location_message`)
15
+ - Envío de mensajes de eventos/calendario (`send_event_message`)
16
+ - Callbacks específicos por grupo (`on_group_message`)
17
+ - Firma de URLs con nombre legible de archivo (`sanitize_filename`)
18
+ - Soporte de progreso en subidas (`progress_callback`)
19
+ - Módulo `stanzas/` reorganizado en subdirectorio
20
+ - Módulo `client/` reorganizado en subdirectorio con mixins
21
+ - `pyproject.toml` moderno (PEP 621)
22
+ - Tests unitarios con pytest
23
+ - CI/CD con GitHub Actions
24
+
25
+ ### Changed
26
+ - Estructura interna reorganizada para claridad
27
+ - Migración de `setup.py` a `pyproject.toml`
28
+
29
+ ## [1.2.0] - 2026-06-01
30
+
31
+ ### Added
32
+ - Envío de stickers (`send_sticker_message`)
33
+ - Envío de contactos (`send_contact_message`)
34
+ - Envío de botones interactivos (`send_button_message`)
35
+ - Edición de mensajes (`edit_message`)
36
+ - Eliminación de mensajes (`delete_message`)
37
+ - Parser incremental de stanzas XMPP (`IncrementalParser`)
38
+
39
+ ## [1.1.0] - 2026-05-15
40
+
41
+ ### Added
42
+ - Envío de imágenes con dimensiones y thumbnail
43
+ - Envío de videos con metadata
44
+ - Subida y descarga de archivos con `FileType`
45
+ - Perfil de usuario (alias, bio, avatar)
46
+ - Utilidades: `format_size`, `get_image_dimensions`, `generate_blurhash`
47
+
48
+ ## [1.0.0] - 2026-05-01
49
+
50
+ ### Added
51
+ - Cliente básico XMPP para ToDus (`ToDusClient`)
52
+ - Cliente stateful con auto-login (`ToDusClient2`)
53
+ - Autenticación por SMS + JWT
54
+ - Envío y recepción de mensajes de texto
55
+ - Manejo de excepciones personalizadas
56
+ - Constantes del protocolo ToDus
57
+
58
+ [1.3.0]: https://github.com/ElJoker63/toDus-API/compare/v1.2.0...v1.3.0
59
+ [1.2.0]: https://github.com/ElJoker63/toDus-API/compare/v1.1.0...v1.2.0
60
+ [1.1.0]: https://github.com/ElJoker63/toDus-API/compare/v1.0.0...v1.1.0
61
+ [1.0.0]: https://github.com/ElJoker63/toDus-API/releases/tag/v1.0.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ElJoker63
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include README.md
2
+ include LICENSE
3
+ include CHANGELOG.md
4
+ include pyproject.toml
@@ -0,0 +1,299 @@
1
+ Metadata-Version: 2.4
2
+ Name: toDus-API
3
+ Version: 1.3.3
4
+ Summary: Cliente Python para ToDus (mensajería cubana) — chat, grupos, archivos, stickers y más
5
+ Author: ElJoker63
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ElJoker63/toDus-API
8
+ Project-URL: Repository, https://github.com/ElJoker63/toDus-API
9
+ Project-URL: Issues, https://github.com/ElJoker63/toDus-API/issues
10
+ Project-URL: Changelog, https://github.com/ElJoker63/toDus-API/blob/main/CHANGELOG.md
11
+ Keywords: todus,cuba,xmpp,messaging,chat
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Communications :: Chat
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: requests
25
+ Requires-Dist: pysocks
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: build; extra == "dev"
29
+ Requires-Dist: twine; extra == "dev"
30
+ Dynamic: license-file
31
+
32
+ <h1>📱 toDus-API</h1>
33
+
34
+ <p align="center">
35
+ <a href="https://pypi.org/project/toDus-API/"><img src="https://img.shields.io/pypi/v/toDus-API" alt="PyPI"></a>
36
+ <a href="https://pypi.org/project/toDus-API/"><img src="https://img.shields.io/pypi/pyversions/toDus-API" alt="Python"></a>
37
+ <a href="https://github.com/ElJoker63/toDus-API/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/ElJoker63/toDus-API/ci.yml?branch=main&label=tests" alt="Tests"></a>
38
+ <a href="https://github.com/ElJoker63/toDus-API/actions/workflows/pypi-publish.yml"><img src="https://img.shields.io/github/actions/workflow/status/ElJoker63/toDus-API/pypi-publish.yml?branch=main&label=publish" alt="Publish"></a>
39
+ <a href="https://github.com/ElJoker63/toDus-API/blob/main/LICENSE"><img src="https://img.shields.io/github/license/ElJoker63/toDus-API" alt="License"></a>
40
+ </p>
41
+
42
+ <p><strong>Cliente Python para ToDus</strong> — la plataforma de mensajería instantánea cubana. Soporta chat privado, grupos MUC Light, archivos, imágenes, videos, stickers, botones interactivos y más.</p>
43
+
44
+ <ul>
45
+ <li><strong>Versión:</strong> 1.3.3</li>
46
+ <li><strong>Python:</strong> >= 3.11</li>
47
+ <li><strong>Autor:</strong> ElJoker63</li>
48
+ <li><strong>Licencia:</strong> MIT</li>
49
+ </ul>
50
+
51
+ <hr>
52
+
53
+ <h2>📦 Instalación</h2>
54
+
55
+ <pre><code>pip install toDus-API</code></pre>
56
+
57
+ <p>O directamente desde el repositorio:</p>
58
+
59
+ <pre><code>pip install git+https://github.com/ElJoker63/toDus-API.git</code></pre>
60
+
61
+ <p>Para desarrollo:</p>
62
+
63
+ <pre><code>git clone https://github.com/ElJoker63/toDus-API.git
64
+ cd toDus-API
65
+ pip install -e ".[dev]"</code></pre>
66
+
67
+ <hr>
68
+
69
+ <h2>🔐 Autenticación (¡Importante!)</h2>
70
+
71
+ <p>ToDus no usa contraseñas elegidas por el usuario. El proceso de autenticación tiene dos pasos:</p>
72
+
73
+ <ol>
74
+ <li>Obtener un token largo (96 caracteres) mediante validación por SMS.</li>
75
+ <li>Usar ese token para hacer login y obtener un JWT de sesión, que se usa para todas las comunicaciones.</li>
76
+ </ol>
77
+
78
+ <p>El cliente <code>ToDusClient2</code> guarda ese token largo en el atributo <code>password</code> (nombre histórico), pero en la práctica debes entenderlo como <code>auth_token</code>.</p>
79
+
80
+ <h3>🔹 Flujo para primera vez (SMS)</h3>
81
+
82
+ <pre><code>from todus import ToDusClient2
83
+
84
+ client = ToDusClient2(phone_number="535xxxxxxx") # sin password aún
85
+
86
+ # 1. Pedir código SMS
87
+ client.request_code() # te llega un PIN de 6 dígitos
88
+
89
+ # 2. Validar el código
90
+ client.validate_code("123456")
91
+ # Ahora client.password contiene el token largo (96 caracteres)
92
+ # ¡Guárdalo en un lugar seguro para futuras sesiones!
93
+
94
+ # 3. Obtener el JWT de sesión
95
+ client.login() # ahora client.logged == True</code></pre>
96
+
97
+ <h3>🔹 Si ya tienes el token largo (de una sesión anterior)</h3>
98
+
99
+ <pre><code>client = ToDusClient2(phone_number="535xxxxxxx", password="ese_token_largo_que_guardaste")
100
+ client.login() # obtiene el JWT internamente</code></pre>
101
+
102
+ <p><strong>⚠️ Importante:</strong> Nunca pases un JWT directamente al constructor. El cliente se encarga de renovarlo automáticamente cuando expira. El parámetro <code>password</code> espera el token largo de 96 caracteres.</p>
103
+
104
+ <hr>
105
+
106
+ <h2>🚀 Uso Rápido</h2>
107
+
108
+ <h3>Enviar mensajes (privados y grupos automáticamente)</h3>
109
+
110
+ <pre><code># Asumiendo que ya hiciste login
111
+ client.send_message("535yyyyyyy", "¡Hola mundo!") # privado
112
+ client.send_message("mi-grupo-id", "Hola grupo!") # grupo (auto-detectado)</code></pre>
113
+
114
+ <h3>Enviar imagen (con subida previa)</h3>
115
+
116
+ <pre><code>from todus import FileType
117
+
118
+ # 1. Subir la imagen
119
+ with open("foto.jpg", "rb") as f:
120
+ image_data = f.read()
121
+ url = client.upload_file(image_data, FileType.PICTURE)
122
+
123
+ # 2. Enviar el mensaje con la imagen
124
+ client.send_image_message(
125
+ "535yyyyyyy",
126
+ url=url,
127
+ file_name="foto.jpg",
128
+ file_size=len(image_data),
129
+ caption="Mi foto"
130
+ )</code></pre>
131
+
132
+ <h3>Escuchar mensajes entrantes</h3>
133
+
134
+ <pre><code>def on_message(msg):
135
+ if msg.get("body"):
136
+ print(f"{msg['from']}: {msg['body']}")
137
+
138
+ client.listen_messages(on_message) # bucle infinito</code></pre>
139
+
140
+ <hr>
141
+
142
+ <h2>🤖 Bot de Ejemplo</h2>
143
+
144
+ <p>En la carpeta <code>examples/</code> encontrarás un bot funcional con comandos:</p>
145
+
146
+ <table>
147
+ <thead>
148
+ <tr>
149
+ <th>Comando</th>
150
+ <th>Respuesta</th>
151
+ </tr>
152
+ </thead>
153
+ <tbody>
154
+ <tr><td><code>/start</code></td><td>Mensaje de bienvenida con lista de comandos</td></tr>
155
+ <tr><td><code>/info</code></td><td>Información sobre la librería</td></tr>
156
+ <tr><td><code>/ping</code></td><td><code>pong</code></td></tr>
157
+ </tbody>
158
+ </table>
159
+
160
+ <p>Ejecútalo con:</p>
161
+
162
+ <pre><code>export TODUS_PHONE=535xxxxxxx
163
+ export TODUS_AUTH_TOKEN=token_largo_de_96_caracteres
164
+ python examples/bot.py</code></pre>
165
+
166
+ <hr>
167
+
168
+ <h2>📡 Tipos de Mensaje Soportados</h2>
169
+
170
+ <p>La librería soporta los siguientes tipos de mensaje:</p>
171
+
172
+ <table>
173
+ <thead>
174
+ <tr>
175
+ <th>Tipo</th>
176
+ <th>Método (ToDusClient2)</th>
177
+ </tr>
178
+ </thead>
179
+ <tbody>
180
+ <tr><td>Texto</td><td><code>send_message(to, body)</code></td></tr>
181
+ <tr><td>Imagen</td><td><code>send_image_message(to, url, file_name, file_size, ...)</code></td></tr>
182
+ <tr><td>Video</td><td><code>send_video_message(to, url, video_id, file_name, ...)</code></td></tr>
183
+ <tr><td>Archivo</td><td><code>send_file_message(to, url, file_type, ...)</code></td></tr>
184
+ <tr><td>Sticker</td><td><code>send_sticker_message(to, sticker_id, ...)</code></td></tr>
185
+ <tr><td>Contacto</td><td><code>send_contact_message(to, contact_id, ...)</code></td></tr>
186
+ <tr><td>Botones</td><td><code>send_button_message(to, text, buttons)</code></td></tr>
187
+ <tr><td>Ubicación</td><td><code>send_location_message(to, lat, lon, ...)</code></td></tr>
188
+ <tr><td>Evento</td><td><code>send_event_message(to, title, start, end, ...)</code></td></tr>
189
+ <tr><td>Editar</td><td><code>edit_message(to, new_body, original_msg_id)</code></td></tr>
190
+ <tr><td>Eliminar</td><td><code>delete_message(to, message_id)</code></td></tr>
191
+ </tbody>
192
+ </table>
193
+
194
+ <p><strong>Auto-detección de destino:</strong> si el <code>to</code> no es un número cubano (10 dígitos empezando por 53), se asume que es un <code>group_id</code> y el mensaje se envía al grupo automáticamente.</p>
195
+
196
+ <hr>
197
+
198
+ <h2>👥 Grupos MUC Light</h2>
199
+
200
+ <pre><code># Unirse a un grupo
201
+ client.groups.join("mi-grupo-id")
202
+
203
+ # Enviar mensaje al grupo (auto-detectado)
204
+ client.send_message("mi-grupo-id", "Hola grupo!")
205
+
206
+ # Callback específico para mensajes de ese grupo
207
+ def on_group_msg(msg):
208
+ print(f"{msg['sender_phone']}: {msg['body']}")
209
+
210
+ client.groups.on_group_message("mi-grupo-id", on_group_msg)
211
+
212
+ # Salir del grupo
213
+ client.groups.leave("mi-grupo-id")</code></pre>
214
+
215
+ <hr>
216
+
217
+ <h2>📤 Subir y Descargar Archivos</h2>
218
+
219
+ <pre><code># Subir cualquier archivo
220
+ with open("documento.pdf", "rb") as f:
221
+ url = client.upload_file(f.read(), FileType.FILE)
222
+
223
+ # Descargar a una carpeta
224
+ size, path = client.download_file_to_folder(url, "./descargas")
225
+ print(f"Descargado {size} bytes en {path}")</code></pre>
226
+
227
+ <hr>
228
+
229
+ <h2>⚠️ Excepciones</h2>
230
+
231
+ <table>
232
+ <thead>
233
+ <tr>
234
+ <th>Excepción</th>
235
+ <th>Cuándo ocurre</th>
236
+ </tr>
237
+ </thead>
238
+ <tbody>
239
+ <tr><td><code>AuthenticationError</code></td><td>Credenciales inválidas o falta autenticación</td></tr>
240
+ <tr><td><code>TokenExpiredError</code></td><td>El token JWT expiró (el cliente lo renueva automáticamente si usas ToDusClient2)</td></tr>
241
+ <tr><td><code>ConnectionLostError</code></td><td>Se perdió la conexión XMPP</td></tr>
242
+ <tr><td><code>UploadError</code></td><td>Error al subir/descargar archivo</td></tr>
243
+ <tr><td><code>GroupError</code></td><td>Error en operación de grupo</td></tr>
244
+ <tr><td><code>ParseError</code></td><td>Stanza malformada</td></tr>
245
+ </tbody>
246
+ </table>
247
+
248
+ <hr>
249
+
250
+ <h2>🗂️ Estructura del Proyecto</h2>
251
+
252
+ <pre><code>toDus-API/
253
+ ├── todus/ # Paquete principal
254
+ │ ├── __init__.py # Exports y versión
255
+ │ ├── client/ # Cliente XMPP/HTTP
256
+ │ │ ├── __init__.py # ToDusClient y ToDusClient2
257
+ │ │ ├── base.py # Conexión y transporte
258
+ │ │ ├── auth.py # Autenticación SMS/JWT
259
+ │ │ ├── message.py # Envío/recepción de mensajes
260
+ │ │ ├── file.py # Subida/descarga de archivos
261
+ │ │ └── profile.py # Perfil de usuario
262
+ │ ├── stanzas/ # Generadores de stanzas XML
263
+ │ │ ├── __init__.py
264
+ │ │ ├── private.py # Chat privado
265
+ │ │ ├── group.py # Chat grupal
266
+ │ │ ├── presence.py # Presencia XMPP
267
+ │ │ └── utils.py # Utilidades de protocolo
268
+ │ ├── group.py # Cliente de grupos MUC Light
269
+ │ ├── parser.py # Parser incremental de stanzas
270
+ │ ├── stanza.py # Re-exports unificados
271
+ │ ├── types.py # Enums (FileType, ChatState, etc.)
272
+ │ ├── util.py # Utilidades (JID, XML, JWT)
273
+ │ ├── constants.py # Hosts, puertos, versiones
274
+ │ └── errors.py # Excepciones personalizadas
275
+ ├── tests/ # Tests unitarios
276
+ │ ├── test_util.py
277
+ │ ├── test_types.py
278
+ │ └── test_stanzas.py
279
+ ├── examples/ # Ejemplos de uso
280
+ │ └── bot.py
281
+ ├── .github/workflows/ # CI/CD
282
+ │ ├── ci.yml # Tests en push/PR
283
+ │ └── pypi-publish.yml # Publicación a PyPI
284
+ ├── pyproject.toml # Configuración del paquete
285
+ ├── LICENSE # Licencia MIT
286
+ ├── CHANGELOG.md # Registro de cambios
287
+ ├── CONTRIBUTING.md # Guía para contribuir
288
+ ├── MANIFEST.in # Archivos incluidos en sdist
289
+ └── README.md # Este archivo</code></pre>
290
+
291
+ <hr>
292
+
293
+ <h2>🔗 Recursos</h2>
294
+
295
+ - **ToDus oficial:** [ToDus](https://web.todus.cu)
296
+ - **Apklis:** [Apklis](https://www.apklis.cu/application/cu.todus.android)
297
+ - **PyPI:** [toDus-API](https://pypi.org/project/toDus-API/)
298
+ - **Changelog:** [CHANGELOG.md](CHANGELOG.md)
299
+ - **Contribuir:** [CONTRIBUTING.md](CONTRIBUTING.md)
@@ -0,0 +1,268 @@
1
+ <h1>📱 toDus-API</h1>
2
+
3
+ <p align="center">
4
+ <a href="https://pypi.org/project/toDus-API/"><img src="https://img.shields.io/pypi/v/toDus-API" alt="PyPI"></a>
5
+ <a href="https://pypi.org/project/toDus-API/"><img src="https://img.shields.io/pypi/pyversions/toDus-API" alt="Python"></a>
6
+ <a href="https://github.com/ElJoker63/toDus-API/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/ElJoker63/toDus-API/ci.yml?branch=main&label=tests" alt="Tests"></a>
7
+ <a href="https://github.com/ElJoker63/toDus-API/actions/workflows/pypi-publish.yml"><img src="https://img.shields.io/github/actions/workflow/status/ElJoker63/toDus-API/pypi-publish.yml?branch=main&label=publish" alt="Publish"></a>
8
+ <a href="https://github.com/ElJoker63/toDus-API/blob/main/LICENSE"><img src="https://img.shields.io/github/license/ElJoker63/toDus-API" alt="License"></a>
9
+ </p>
10
+
11
+ <p><strong>Cliente Python para ToDus</strong> — la plataforma de mensajería instantánea cubana. Soporta chat privado, grupos MUC Light, archivos, imágenes, videos, stickers, botones interactivos y más.</p>
12
+
13
+ <ul>
14
+ <li><strong>Versión:</strong> 1.3.3</li>
15
+ <li><strong>Python:</strong> >= 3.11</li>
16
+ <li><strong>Autor:</strong> ElJoker63</li>
17
+ <li><strong>Licencia:</strong> MIT</li>
18
+ </ul>
19
+
20
+ <hr>
21
+
22
+ <h2>📦 Instalación</h2>
23
+
24
+ <pre><code>pip install toDus-API</code></pre>
25
+
26
+ <p>O directamente desde el repositorio:</p>
27
+
28
+ <pre><code>pip install git+https://github.com/ElJoker63/toDus-API.git</code></pre>
29
+
30
+ <p>Para desarrollo:</p>
31
+
32
+ <pre><code>git clone https://github.com/ElJoker63/toDus-API.git
33
+ cd toDus-API
34
+ pip install -e ".[dev]"</code></pre>
35
+
36
+ <hr>
37
+
38
+ <h2>🔐 Autenticación (¡Importante!)</h2>
39
+
40
+ <p>ToDus no usa contraseñas elegidas por el usuario. El proceso de autenticación tiene dos pasos:</p>
41
+
42
+ <ol>
43
+ <li>Obtener un token largo (96 caracteres) mediante validación por SMS.</li>
44
+ <li>Usar ese token para hacer login y obtener un JWT de sesión, que se usa para todas las comunicaciones.</li>
45
+ </ol>
46
+
47
+ <p>El cliente <code>ToDusClient2</code> guarda ese token largo en el atributo <code>password</code> (nombre histórico), pero en la práctica debes entenderlo como <code>auth_token</code>.</p>
48
+
49
+ <h3>🔹 Flujo para primera vez (SMS)</h3>
50
+
51
+ <pre><code>from todus import ToDusClient2
52
+
53
+ client = ToDusClient2(phone_number="535xxxxxxx") # sin password aún
54
+
55
+ # 1. Pedir código SMS
56
+ client.request_code() # te llega un PIN de 6 dígitos
57
+
58
+ # 2. Validar el código
59
+ client.validate_code("123456")
60
+ # Ahora client.password contiene el token largo (96 caracteres)
61
+ # ¡Guárdalo en un lugar seguro para futuras sesiones!
62
+
63
+ # 3. Obtener el JWT de sesión
64
+ client.login() # ahora client.logged == True</code></pre>
65
+
66
+ <h3>🔹 Si ya tienes el token largo (de una sesión anterior)</h3>
67
+
68
+ <pre><code>client = ToDusClient2(phone_number="535xxxxxxx", password="ese_token_largo_que_guardaste")
69
+ client.login() # obtiene el JWT internamente</code></pre>
70
+
71
+ <p><strong>⚠️ Importante:</strong> Nunca pases un JWT directamente al constructor. El cliente se encarga de renovarlo automáticamente cuando expira. El parámetro <code>password</code> espera el token largo de 96 caracteres.</p>
72
+
73
+ <hr>
74
+
75
+ <h2>🚀 Uso Rápido</h2>
76
+
77
+ <h3>Enviar mensajes (privados y grupos automáticamente)</h3>
78
+
79
+ <pre><code># Asumiendo que ya hiciste login
80
+ client.send_message("535yyyyyyy", "¡Hola mundo!") # privado
81
+ client.send_message("mi-grupo-id", "Hola grupo!") # grupo (auto-detectado)</code></pre>
82
+
83
+ <h3>Enviar imagen (con subida previa)</h3>
84
+
85
+ <pre><code>from todus import FileType
86
+
87
+ # 1. Subir la imagen
88
+ with open("foto.jpg", "rb") as f:
89
+ image_data = f.read()
90
+ url = client.upload_file(image_data, FileType.PICTURE)
91
+
92
+ # 2. Enviar el mensaje con la imagen
93
+ client.send_image_message(
94
+ "535yyyyyyy",
95
+ url=url,
96
+ file_name="foto.jpg",
97
+ file_size=len(image_data),
98
+ caption="Mi foto"
99
+ )</code></pre>
100
+
101
+ <h3>Escuchar mensajes entrantes</h3>
102
+
103
+ <pre><code>def on_message(msg):
104
+ if msg.get("body"):
105
+ print(f"{msg['from']}: {msg['body']}")
106
+
107
+ client.listen_messages(on_message) # bucle infinito</code></pre>
108
+
109
+ <hr>
110
+
111
+ <h2>🤖 Bot de Ejemplo</h2>
112
+
113
+ <p>En la carpeta <code>examples/</code> encontrarás un bot funcional con comandos:</p>
114
+
115
+ <table>
116
+ <thead>
117
+ <tr>
118
+ <th>Comando</th>
119
+ <th>Respuesta</th>
120
+ </tr>
121
+ </thead>
122
+ <tbody>
123
+ <tr><td><code>/start</code></td><td>Mensaje de bienvenida con lista de comandos</td></tr>
124
+ <tr><td><code>/info</code></td><td>Información sobre la librería</td></tr>
125
+ <tr><td><code>/ping</code></td><td><code>pong</code></td></tr>
126
+ </tbody>
127
+ </table>
128
+
129
+ <p>Ejecútalo con:</p>
130
+
131
+ <pre><code>export TODUS_PHONE=535xxxxxxx
132
+ export TODUS_AUTH_TOKEN=token_largo_de_96_caracteres
133
+ python examples/bot.py</code></pre>
134
+
135
+ <hr>
136
+
137
+ <h2>📡 Tipos de Mensaje Soportados</h2>
138
+
139
+ <p>La librería soporta los siguientes tipos de mensaje:</p>
140
+
141
+ <table>
142
+ <thead>
143
+ <tr>
144
+ <th>Tipo</th>
145
+ <th>Método (ToDusClient2)</th>
146
+ </tr>
147
+ </thead>
148
+ <tbody>
149
+ <tr><td>Texto</td><td><code>send_message(to, body)</code></td></tr>
150
+ <tr><td>Imagen</td><td><code>send_image_message(to, url, file_name, file_size, ...)</code></td></tr>
151
+ <tr><td>Video</td><td><code>send_video_message(to, url, video_id, file_name, ...)</code></td></tr>
152
+ <tr><td>Archivo</td><td><code>send_file_message(to, url, file_type, ...)</code></td></tr>
153
+ <tr><td>Sticker</td><td><code>send_sticker_message(to, sticker_id, ...)</code></td></tr>
154
+ <tr><td>Contacto</td><td><code>send_contact_message(to, contact_id, ...)</code></td></tr>
155
+ <tr><td>Botones</td><td><code>send_button_message(to, text, buttons)</code></td></tr>
156
+ <tr><td>Ubicación</td><td><code>send_location_message(to, lat, lon, ...)</code></td></tr>
157
+ <tr><td>Evento</td><td><code>send_event_message(to, title, start, end, ...)</code></td></tr>
158
+ <tr><td>Editar</td><td><code>edit_message(to, new_body, original_msg_id)</code></td></tr>
159
+ <tr><td>Eliminar</td><td><code>delete_message(to, message_id)</code></td></tr>
160
+ </tbody>
161
+ </table>
162
+
163
+ <p><strong>Auto-detección de destino:</strong> si el <code>to</code> no es un número cubano (10 dígitos empezando por 53), se asume que es un <code>group_id</code> y el mensaje se envía al grupo automáticamente.</p>
164
+
165
+ <hr>
166
+
167
+ <h2>👥 Grupos MUC Light</h2>
168
+
169
+ <pre><code># Unirse a un grupo
170
+ client.groups.join("mi-grupo-id")
171
+
172
+ # Enviar mensaje al grupo (auto-detectado)
173
+ client.send_message("mi-grupo-id", "Hola grupo!")
174
+
175
+ # Callback específico para mensajes de ese grupo
176
+ def on_group_msg(msg):
177
+ print(f"{msg['sender_phone']}: {msg['body']}")
178
+
179
+ client.groups.on_group_message("mi-grupo-id", on_group_msg)
180
+
181
+ # Salir del grupo
182
+ client.groups.leave("mi-grupo-id")</code></pre>
183
+
184
+ <hr>
185
+
186
+ <h2>📤 Subir y Descargar Archivos</h2>
187
+
188
+ <pre><code># Subir cualquier archivo
189
+ with open("documento.pdf", "rb") as f:
190
+ url = client.upload_file(f.read(), FileType.FILE)
191
+
192
+ # Descargar a una carpeta
193
+ size, path = client.download_file_to_folder(url, "./descargas")
194
+ print(f"Descargado {size} bytes en {path}")</code></pre>
195
+
196
+ <hr>
197
+
198
+ <h2>⚠️ Excepciones</h2>
199
+
200
+ <table>
201
+ <thead>
202
+ <tr>
203
+ <th>Excepción</th>
204
+ <th>Cuándo ocurre</th>
205
+ </tr>
206
+ </thead>
207
+ <tbody>
208
+ <tr><td><code>AuthenticationError</code></td><td>Credenciales inválidas o falta autenticación</td></tr>
209
+ <tr><td><code>TokenExpiredError</code></td><td>El token JWT expiró (el cliente lo renueva automáticamente si usas ToDusClient2)</td></tr>
210
+ <tr><td><code>ConnectionLostError</code></td><td>Se perdió la conexión XMPP</td></tr>
211
+ <tr><td><code>UploadError</code></td><td>Error al subir/descargar archivo</td></tr>
212
+ <tr><td><code>GroupError</code></td><td>Error en operación de grupo</td></tr>
213
+ <tr><td><code>ParseError</code></td><td>Stanza malformada</td></tr>
214
+ </tbody>
215
+ </table>
216
+
217
+ <hr>
218
+
219
+ <h2>🗂️ Estructura del Proyecto</h2>
220
+
221
+ <pre><code>toDus-API/
222
+ ├── todus/ # Paquete principal
223
+ │ ├── __init__.py # Exports y versión
224
+ │ ├── client/ # Cliente XMPP/HTTP
225
+ │ │ ├── __init__.py # ToDusClient y ToDusClient2
226
+ │ │ ├── base.py # Conexión y transporte
227
+ │ │ ├── auth.py # Autenticación SMS/JWT
228
+ │ │ ├── message.py # Envío/recepción de mensajes
229
+ │ │ ├── file.py # Subida/descarga de archivos
230
+ │ │ └── profile.py # Perfil de usuario
231
+ │ ├── stanzas/ # Generadores de stanzas XML
232
+ │ │ ├── __init__.py
233
+ │ │ ├── private.py # Chat privado
234
+ │ │ ├── group.py # Chat grupal
235
+ │ │ ├── presence.py # Presencia XMPP
236
+ │ │ └── utils.py # Utilidades de protocolo
237
+ │ ├── group.py # Cliente de grupos MUC Light
238
+ │ ├── parser.py # Parser incremental de stanzas
239
+ │ ├── stanza.py # Re-exports unificados
240
+ │ ├── types.py # Enums (FileType, ChatState, etc.)
241
+ │ ├── util.py # Utilidades (JID, XML, JWT)
242
+ │ ├── constants.py # Hosts, puertos, versiones
243
+ │ └── errors.py # Excepciones personalizadas
244
+ ├── tests/ # Tests unitarios
245
+ │ ├── test_util.py
246
+ │ ├── test_types.py
247
+ │ └── test_stanzas.py
248
+ ├── examples/ # Ejemplos de uso
249
+ │ └── bot.py
250
+ ├── .github/workflows/ # CI/CD
251
+ │ ├── ci.yml # Tests en push/PR
252
+ │ └── pypi-publish.yml # Publicación a PyPI
253
+ ├── pyproject.toml # Configuración del paquete
254
+ ├── LICENSE # Licencia MIT
255
+ ├── CHANGELOG.md # Registro de cambios
256
+ ├── CONTRIBUTING.md # Guía para contribuir
257
+ ├── MANIFEST.in # Archivos incluidos en sdist
258
+ └── README.md # Este archivo</code></pre>
259
+
260
+ <hr>
261
+
262
+ <h2>🔗 Recursos</h2>
263
+
264
+ - **ToDus oficial:** [ToDus](https://web.todus.cu)
265
+ - **Apklis:** [Apklis](https://www.apklis.cu/application/cu.todus.android)
266
+ - **PyPI:** [toDus-API](https://pypi.org/project/toDus-API/)
267
+ - **Changelog:** [CHANGELOG.md](CHANGELOG.md)
268
+ - **Contribuir:** [CONTRIBUTING.md](CONTRIBUTING.md)