universal-mcp-applications 0.1.21__py3-none-any.whl → 0.1.23__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.

Potentially problematic release.


This version of universal-mcp-applications might be problematic. Click here for more details.

Files changed (78) hide show
  1. universal_mcp/applications/BEST_PRACTICES.md +166 -0
  2. universal_mcp/applications/airtable/app.py +0 -1
  3. universal_mcp/applications/apollo/app.py +0 -1
  4. universal_mcp/applications/aws_s3/app.py +40 -39
  5. universal_mcp/applications/browser_use/README.md +1 -0
  6. universal_mcp/applications/browser_use/__init__.py +0 -0
  7. universal_mcp/applications/browser_use/app.py +71 -0
  8. universal_mcp/applications/calendly/app.py +125 -125
  9. universal_mcp/applications/canva/app.py +95 -99
  10. universal_mcp/applications/confluence/app.py +0 -1
  11. universal_mcp/applications/contentful/app.py +4 -5
  12. universal_mcp/applications/domain_checker/app.py +11 -15
  13. universal_mcp/applications/e2b/app.py +4 -4
  14. universal_mcp/applications/elevenlabs/app.py +18 -15
  15. universal_mcp/applications/exa/app.py +17 -17
  16. universal_mcp/applications/falai/app.py +28 -29
  17. universal_mcp/applications/file_system/app.py +9 -9
  18. universal_mcp/applications/firecrawl/app.py +36 -36
  19. universal_mcp/applications/fireflies/app.py +55 -56
  20. universal_mcp/applications/fpl/app.py +49 -50
  21. universal_mcp/applications/ghost_content/app.py +0 -1
  22. universal_mcp/applications/github/app.py +41 -43
  23. universal_mcp/applications/google_calendar/app.py +40 -39
  24. universal_mcp/applications/google_docs/app.py +168 -232
  25. universal_mcp/applications/google_drive/app.py +212 -215
  26. universal_mcp/applications/google_gemini/app.py +1 -5
  27. universal_mcp/applications/google_mail/app.py +91 -90
  28. universal_mcp/applications/google_searchconsole/app.py +29 -29
  29. universal_mcp/applications/google_sheet/app.py +115 -115
  30. universal_mcp/applications/hashnode/README.md +6 -3
  31. universal_mcp/applications/hashnode/app.py +174 -25
  32. universal_mcp/applications/http_tools/app.py +10 -11
  33. universal_mcp/applications/hubspot/__init__.py +1 -1
  34. universal_mcp/applications/hubspot/api_segments/api_segment_base.py +36 -7
  35. universal_mcp/applications/hubspot/api_segments/crm_api.py +368 -368
  36. universal_mcp/applications/hubspot/api_segments/marketing_api.py +115 -115
  37. universal_mcp/applications/hubspot/app.py +131 -72
  38. universal_mcp/applications/jira/app.py +0 -1
  39. universal_mcp/applications/linkedin/app.py +20 -20
  40. universal_mcp/applications/markitdown/app.py +10 -5
  41. universal_mcp/applications/ms_teams/app.py +123 -123
  42. universal_mcp/applications/openai/app.py +40 -39
  43. universal_mcp/applications/outlook/app.py +32 -32
  44. universal_mcp/applications/perplexity/app.py +4 -4
  45. universal_mcp/applications/reddit/app.py +69 -70
  46. universal_mcp/applications/resend/app.py +116 -117
  47. universal_mcp/applications/rocketlane/app.py +0 -1
  48. universal_mcp/applications/scraper/__init__.py +1 -1
  49. universal_mcp/applications/scraper/app.py +80 -81
  50. universal_mcp/applications/serpapi/app.py +14 -14
  51. universal_mcp/applications/sharepoint/app.py +19 -20
  52. universal_mcp/applications/shopify/app.py +0 -1
  53. universal_mcp/applications/slack/app.py +48 -48
  54. universal_mcp/applications/tavily/app.py +4 -4
  55. universal_mcp/applications/twitter/api_segments/compliance_api.py +13 -15
  56. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +20 -20
  57. universal_mcp/applications/twitter/api_segments/dm_events_api.py +12 -12
  58. universal_mcp/applications/twitter/api_segments/likes_api.py +12 -12
  59. universal_mcp/applications/twitter/api_segments/lists_api.py +37 -39
  60. universal_mcp/applications/twitter/api_segments/spaces_api.py +24 -24
  61. universal_mcp/applications/twitter/api_segments/trends_api.py +4 -4
  62. universal_mcp/applications/twitter/api_segments/tweets_api.py +105 -105
  63. universal_mcp/applications/twitter/api_segments/usage_api.py +4 -4
  64. universal_mcp/applications/twitter/api_segments/users_api.py +136 -136
  65. universal_mcp/applications/twitter/app.py +6 -2
  66. universal_mcp/applications/unipile/app.py +90 -97
  67. universal_mcp/applications/whatsapp/app.py +53 -54
  68. universal_mcp/applications/whatsapp/audio.py +39 -35
  69. universal_mcp/applications/whatsapp/whatsapp.py +176 -154
  70. universal_mcp/applications/whatsapp_business/app.py +92 -92
  71. universal_mcp/applications/yahoo_finance/app.py +105 -63
  72. universal_mcp/applications/youtube/app.py +193 -196
  73. universal_mcp/applications/zenquotes/__init__.py +2 -0
  74. universal_mcp/applications/zenquotes/app.py +5 -5
  75. {universal_mcp_applications-0.1.21.dist-info → universal_mcp_applications-0.1.23.dist-info}/METADATA +2 -1
  76. {universal_mcp_applications-0.1.21.dist-info → universal_mcp_applications-0.1.23.dist-info}/RECORD +78 -74
  77. {universal_mcp_applications-0.1.21.dist-info → universal_mcp_applications-0.1.23.dist-info}/WHEEL +0 -0
  78. {universal_mcp_applications-0.1.21.dist-info → universal_mcp_applications-0.1.23.dist-info}/licenses/LICENSE +0 -0
@@ -1,15 +1,17 @@
1
- import requests
2
1
  import json
3
- from datetime import datetime
4
- from dataclasses import dataclass
5
- from typing import Optional, List, Tuple
6
2
  import os.path
7
- from . import audio
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+
6
+ import requests
8
7
  from dotenv import load_dotenv
9
8
 
9
+ from . import audio
10
+
10
11
  load_dotenv()
11
12
 
12
- WHATSAPP_API_BASE_URL = os.getenv('WHATSAPP_API_BASE_URL', "http://134.209.144.43:8080")
13
+ WHATSAPP_API_BASE_URL = os.getenv("WHATSAPP_API_BASE_URL", "http://134.209.144.43:8080")
14
+
13
15
 
14
16
  @dataclass
15
17
  class Message:
@@ -19,45 +21,51 @@ class Message:
19
21
  is_from_me: bool
20
22
  chat_jid: str
21
23
  id: str
22
- chat_name: Optional[str] = None
23
- media_type: Optional[str] = None
24
+ chat_name: str | None = None
25
+ media_type: str | None = None
26
+
24
27
 
25
28
  @dataclass
26
29
  class Chat:
27
30
  jid: str
28
- name: Optional[str]
29
- last_message_time: Optional[datetime]
30
- last_message: Optional[str] = None
31
- last_sender: Optional[str] = None
32
- last_is_from_me: Optional[bool] = None
31
+ name: str | None
32
+ last_message_time: datetime | None
33
+ last_message: str | None = None
34
+ last_sender: str | None = None
35
+ last_is_from_me: bool | None = None
33
36
 
34
37
  @property
35
38
  def is_group(self) -> bool:
36
39
  """Determine if chat is a group based on JID pattern."""
37
40
  return self.jid.endswith("@g.us")
38
41
 
42
+
39
43
  @dataclass
40
44
  class Contact:
41
45
  phone_number: str
42
- name: Optional[str]
46
+ name: str | None
43
47
  jid: str
44
48
 
49
+
45
50
  @dataclass
46
51
  class MessageContext:
47
52
  message: Message
48
- before: List[Message]
49
- after: List[Message]
53
+ before: list[Message]
54
+ after: list[Message]
55
+
50
56
 
51
- def _make_api_request(endpoint: str, method: str = "GET", data: dict = None, user_id: str = "default_user") -> dict:
57
+ def _make_api_request(
58
+ endpoint: str, method: str = "GET", data: dict = None, user_id: str = "default_user"
59
+ ) -> dict:
52
60
  """Make HTTP request to WhatsApp Bridge API."""
53
61
  url = f"{WHATSAPP_API_BASE_URL}/api/{endpoint}"
54
-
62
+
55
63
  # Add user_id to query parameters for GET requests
56
64
  if method.upper() == "GET" and data:
57
65
  data["user_id"] = user_id
58
66
  elif method.upper() == "GET":
59
67
  data = {"user_id": user_id}
60
-
68
+
61
69
  try:
62
70
  if method.upper() == "GET":
63
71
  response = requests.get(url, params=data, timeout=30)
@@ -65,68 +73,80 @@ def _make_api_request(endpoint: str, method: str = "GET", data: dict = None, use
65
73
  response = requests.post(url, json=data, timeout=30)
66
74
  else:
67
75
  raise ValueError(f"Unsupported HTTP method: {method}")
68
-
76
+
69
77
  if response.status_code == 200:
70
78
  return response.json()
71
79
  else:
72
80
  return {"error": f"HTTP {response.status_code}: {response.text}"}
73
-
81
+
74
82
  except requests.RequestException as e:
75
83
  return {"error": f"Request failed: {str(e)}"}
76
84
  except json.JSONDecodeError:
77
85
  return {"error": f"Invalid JSON response: {response.text}"}
78
86
 
87
+
79
88
  def get_sender_name(sender_jid: str, user_id: str = "default_user") -> str:
80
89
  """Get sender name via API call."""
81
- result = _make_api_request("sender_name", data={"sender_jid": sender_jid}, user_id=user_id)
82
-
90
+ result = _make_api_request(
91
+ "sender_name", data={"sender_jid": sender_jid}, user_id=user_id
92
+ )
93
+
83
94
  if "error" in result:
84
95
  return sender_jid
85
-
96
+
86
97
  return result.get("name", sender_jid)
87
98
 
88
- def format_message(message: Message, show_chat_info: bool = True, user_id: str = "default_user") -> str:
99
+
100
+ def format_message(
101
+ message: Message, show_chat_info: bool = True, user_id: str = "default_user"
102
+ ) -> str:
89
103
  """Print a single message with consistent formatting."""
90
104
  output = ""
91
-
105
+
92
106
  if show_chat_info and message.chat_name:
93
107
  output += f"[{message.timestamp:%Y-%m-%d %H:%M:%S}] Chat: {message.chat_name} "
94
108
  else:
95
109
  output += f"[{message.timestamp:%Y-%m-%d %H:%M:%S}] "
96
-
110
+
97
111
  content_prefix = ""
98
- if hasattr(message, 'media_type') and message.media_type:
112
+ if hasattr(message, "media_type") and message.media_type:
99
113
  content_prefix = f"[{message.media_type} - Message ID: {message.id} - Chat JID: {message.chat_jid}] "
100
-
114
+
101
115
  try:
102
- sender_name = get_sender_name(message.sender, user_id) if not message.is_from_me else "Me"
116
+ sender_name = (
117
+ get_sender_name(message.sender, user_id) if not message.is_from_me else "Me"
118
+ )
103
119
  output += f"From: {sender_name}: {content_prefix}{message.content}\n"
104
- except Exception as e:
105
- print(f"Error formatting message: {e}")
120
+ except Exception:
121
+ pass
106
122
  return output
107
123
 
108
- def format_messages_list(messages: List[Message], show_chat_info: bool = True, user_id: str = "default_user") -> str:
124
+
125
+ def format_messages_list(
126
+ messages: list[Message], show_chat_info: bool = True, user_id: str = "default_user"
127
+ ) -> str:
109
128
  output = ""
110
129
  if not messages:
111
130
  output += "No messages to display."
112
131
  return output
113
-
132
+
114
133
  for message in messages:
115
134
  output += format_message(message, show_chat_info, user_id)
116
135
  return output
117
136
 
137
+
118
138
  def list_messages(
119
- after: Optional[str] = None,
120
- before: Optional[str] = None,
121
- sender_phone_number: Optional[str] = None,
122
- chat_jid: Optional[str] = None,
123
- query: Optional[str] = None,
139
+ after: str | None = None,
140
+ before: str | None = None,
141
+ sender_phone_number: str | None = None,
142
+ chat_jid: str | None = None,
143
+ query: str | None = None,
124
144
  limit: int = 20,
125
145
  page: int = 0,
126
146
  include_context: bool = True,
127
147
  context_before: int = 1,
128
148
  context_after: int = 1,
129
- user_id: str = "default_user"
149
+ user_id: str = "default_user",
130
150
  ) -> str:
131
151
  """Get messages matching the specified criteria with optional context via API."""
132
152
  params = {
@@ -139,260 +159,262 @@ def list_messages(
139
159
  "page": page,
140
160
  "include_context": include_context,
141
161
  "context_before": context_before,
142
- "context_after": context_after
162
+ "context_after": context_after,
143
163
  }
144
-
164
+
145
165
  # Remove None values
146
166
  params = {k: v for k, v in params.items() if v is not None}
147
-
167
+
148
168
  result = _make_api_request("messages", data=params, user_id=user_id)
149
-
169
+
150
170
  if "error" in result:
151
171
  return f"Error retrieving messages: {result['error']}"
152
-
172
+
153
173
  return result.get("messages", "No messages found")
154
174
 
175
+
155
176
  def get_message_context(
156
- message_id: str,
157
- before: int = 5,
158
- after: int = 5,
159
- user_id: str = "default_user"
177
+ message_id: str, before: int = 5, after: int = 5, user_id: str = "default_user"
160
178
  ) -> MessageContext:
161
179
  """Get context around a specific message via API."""
162
- params = {
163
- "message_id": message_id,
164
- "before": before,
165
- "after": after
166
- }
167
-
180
+ params = {"message_id": message_id, "before": before, "after": after}
181
+
168
182
  result = _make_api_request("message_context", data=params, user_id=user_id)
169
-
183
+
170
184
  if "error" in result:
171
185
  raise ValueError(f"Error getting message context: {result['error']}")
172
-
186
+
173
187
  # Parse the response into MessageContext object
174
188
  # This would need to be implemented based on the API response structure
175
189
  # For now, returning a simple error message
176
190
  raise NotImplementedError("Message context API not yet implemented in bridge")
177
191
 
192
+
178
193
  def list_chats(
179
- query: Optional[str] = None,
194
+ query: str | None = None,
180
195
  limit: int = 20,
181
196
  page: int = 0,
182
197
  include_last_message: bool = True,
183
198
  sort_by: str = "last_active",
184
- user_id: str = "default_user"
185
- ) -> List[Chat]:
199
+ user_id: str = "default_user",
200
+ ) -> list[Chat]:
186
201
  """Get chats matching the specified criteria via API."""
187
202
  params = {
188
203
  "query": query,
189
204
  "limit": limit,
190
205
  "page": page,
191
206
  "include_last_message": include_last_message,
192
- "sort_by": sort_by
207
+ "sort_by": sort_by,
193
208
  }
194
-
209
+
195
210
  # Remove None values
196
211
  params = {k: v for k, v in params.items() if v is not None}
197
-
212
+
198
213
  result = _make_api_request("chats", data=params, user_id=user_id)
199
-
214
+
200
215
  if "error" in result:
201
- print(f"Error retrieving chats: {result['error']}")
202
216
  return []
203
-
217
+
204
218
  chats_data = result.get("chats", [])
205
219
  chats = []
206
-
220
+
207
221
  for chat_data in chats_data:
208
222
  chat = Chat(
209
223
  jid=chat_data["jid"],
210
224
  name=chat_data.get("name"),
211
- last_message_time=datetime.fromisoformat(chat_data["last_message_time"]) if chat_data.get("last_message_time") else None,
225
+ last_message_time=datetime.fromisoformat(chat_data["last_message_time"])
226
+ if chat_data.get("last_message_time")
227
+ else None,
212
228
  last_message=chat_data.get("last_message"),
213
229
  last_sender=chat_data.get("last_sender"),
214
- last_is_from_me=chat_data.get("last_is_from_me")
230
+ last_is_from_me=chat_data.get("last_is_from_me"),
215
231
  )
216
232
  chats.append(chat)
217
-
233
+
218
234
  return chats
219
235
 
220
- def search_contacts(query: str, user_id: str = "default_user") -> List[Contact]:
236
+
237
+ def search_contacts(query: str, user_id: str = "default_user") -> list[Contact]:
221
238
  """Search contacts by name or phone number via API."""
222
239
  result = _make_api_request("contacts", data={"query": query}, user_id=user_id)
223
-
240
+
224
241
  if "error" in result:
225
- print(f"Error searching contacts: {result['error']}")
226
242
  return []
227
-
243
+
228
244
  contacts_data = result.get("contacts", [])
229
245
  contacts = []
230
-
246
+
231
247
  for contact_data in contacts_data:
232
248
  contact = Contact(
233
249
  phone_number=contact_data["phone_number"],
234
250
  name=contact_data.get("name"),
235
- jid=contact_data["jid"]
251
+ jid=contact_data["jid"],
236
252
  )
237
253
  contacts.append(contact)
238
-
254
+
239
255
  return contacts
240
256
 
241
- def get_contact_chats(jid: str, limit: int = 20, page: int = 0, user_id: str = "default_user") -> List[Chat]:
257
+
258
+ def get_contact_chats(
259
+ jid: str, limit: int = 20, page: int = 0, user_id: str = "default_user"
260
+ ) -> list[Chat]:
242
261
  """Get all chats involving the contact via API."""
243
- params = {
244
- "jid": jid,
245
- "limit": limit,
246
- "page": page
247
- }
248
-
262
+ params = {"jid": jid, "limit": limit, "page": page}
263
+
249
264
  result = _make_api_request("contact_chats", data=params, user_id=user_id)
250
-
265
+
251
266
  if "error" in result:
252
- print(f"Error getting contact chats: {result['error']}")
253
267
  return []
254
-
268
+
255
269
  chats_data = result.get("chats", [])
256
270
  chats = []
257
-
271
+
258
272
  for chat_data in chats_data:
259
273
  chat = Chat(
260
274
  jid=chat_data["jid"],
261
275
  name=chat_data.get("name"),
262
- last_message_time=datetime.fromisoformat(chat_data["last_message_time"]) if chat_data.get("last_message_time") else None,
276
+ last_message_time=datetime.fromisoformat(chat_data["last_message_time"])
277
+ if chat_data.get("last_message_time")
278
+ else None,
263
279
  last_message=chat_data.get("last_message"),
264
280
  last_sender=chat_data.get("last_sender"),
265
- last_is_from_me=chat_data.get("last_is_from_me")
281
+ last_is_from_me=chat_data.get("last_is_from_me"),
266
282
  )
267
283
  chats.append(chat)
268
-
284
+
269
285
  return chats
270
286
 
287
+
271
288
  def get_last_interaction(jid: str, user_id: str = "default_user") -> str:
272
289
  """Get most recent message involving the contact via API."""
273
290
  result = _make_api_request("last_interaction", data={"jid": jid}, user_id=user_id)
274
-
291
+
275
292
  if "error" in result:
276
293
  return f"Error getting last interaction: {result['error']}"
277
-
294
+
278
295
  return result.get("message", "No interaction found")
279
296
 
280
- def get_chat(chat_jid: str, include_last_message: bool = True, user_id: str = "default_user") -> Optional[Chat]:
297
+
298
+ def get_chat(
299
+ chat_jid: str, include_last_message: bool = True, user_id: str = "default_user"
300
+ ) -> Chat | None:
281
301
  """Get chat metadata by JID via API."""
282
- params = {
283
- "chat_jid": chat_jid,
284
- "include_last_message": include_last_message
285
- }
286
-
302
+ params = {"chat_jid": chat_jid, "include_last_message": include_last_message}
303
+
287
304
  result = _make_api_request("chat", data=params, user_id=user_id)
288
-
305
+
289
306
  if "error" in result:
290
- print(f"Error getting chat: {result['error']}")
291
307
  return None
292
-
308
+
293
309
  chat_data = result.get("chat")
294
310
  if not chat_data:
295
311
  return None
296
-
312
+
297
313
  return Chat(
298
314
  jid=chat_data["jid"],
299
315
  name=chat_data.get("name"),
300
- last_message_time=datetime.fromisoformat(chat_data["last_message_time"]) if chat_data.get("last_message_time") else None,
316
+ last_message_time=datetime.fromisoformat(chat_data["last_message_time"])
317
+ if chat_data.get("last_message_time")
318
+ else None,
301
319
  last_message=chat_data.get("last_message"),
302
320
  last_sender=chat_data.get("last_sender"),
303
- last_is_from_me=chat_data.get("last_is_from_me")
321
+ last_is_from_me=chat_data.get("last_is_from_me"),
304
322
  )
305
323
 
306
- def get_direct_chat_by_contact(sender_phone_number: str, user_id: str = "default_user") -> Optional[Chat]:
324
+
325
+ def get_direct_chat_by_contact(
326
+ sender_phone_number: str, user_id: str = "default_user"
327
+ ) -> Chat | None:
307
328
  """Get chat metadata by sender phone number via API."""
308
- result = _make_api_request("direct_chat", data={"sender_phone_number": sender_phone_number}, user_id=user_id)
309
-
329
+ result = _make_api_request(
330
+ "direct_chat",
331
+ data={"sender_phone_number": sender_phone_number},
332
+ user_id=user_id,
333
+ )
334
+
310
335
  if "error" in result:
311
- print(f"Error getting direct chat: {result['error']}")
312
336
  return None
313
-
337
+
314
338
  chat_data = result.get("chat")
315
339
  if not chat_data:
316
340
  return None
317
-
341
+
318
342
  return Chat(
319
343
  jid=chat_data["jid"],
320
344
  name=chat_data.get("name"),
321
- last_message_time=datetime.fromisoformat(chat_data["last_message_time"]) if chat_data.get("last_message_time") else None,
345
+ last_message_time=datetime.fromisoformat(chat_data["last_message_time"])
346
+ if chat_data.get("last_message_time")
347
+ else None,
322
348
  last_message=chat_data.get("last_message"),
323
349
  last_sender=chat_data.get("last_sender"),
324
- last_is_from_me=chat_data.get("last_is_from_me")
350
+ last_is_from_me=chat_data.get("last_is_from_me"),
325
351
  )
326
352
 
327
- def send_message(recipient: str, message: str, user_id: str = "default_user") -> Tuple[bool, str]:
353
+
354
+ def send_message(
355
+ recipient: str, message: str, user_id: str = "default_user"
356
+ ) -> tuple[bool, str]:
328
357
  """Send message via API."""
329
- payload = {
330
- "user_id": user_id,
331
- "recipient": recipient,
332
- "message": message
333
- }
334
-
358
+ payload = {"user_id": user_id, "recipient": recipient, "message": message}
359
+
335
360
  result = _make_api_request("send", method="POST", data=payload, user_id=user_id)
336
-
361
+
337
362
  if "error" in result:
338
363
  return False, result["error"]
339
-
364
+
340
365
  return result.get("success", False), result.get("message", "Unknown response")
341
366
 
342
- def send_file(recipient: str, media_path: str, user_id: str = "default_user") -> Tuple[bool, str]:
367
+
368
+ def send_file(
369
+ recipient: str, media_path: str, user_id: str = "default_user"
370
+ ) -> tuple[bool, str]:
343
371
  """Send file via API."""
344
- payload = {
345
- "user_id": user_id,
346
- "recipient": recipient,
347
- "media_path": media_path
348
- }
349
-
372
+ payload = {"user_id": user_id, "recipient": recipient, "media_path": media_path}
373
+
350
374
  result = _make_api_request("send", method="POST", data=payload, user_id=user_id)
351
-
375
+
352
376
  if "error" in result:
353
377
  return False, result["error"]
354
-
378
+
355
379
  return result.get("success", False), result.get("message", "Unknown response")
356
380
 
357
- def send_audio_message(recipient: str, media_path: str, user_id: str = "default_user") -> Tuple[bool, str]:
381
+
382
+ def send_audio_message(
383
+ recipient: str, media_path: str, user_id: str = "default_user"
384
+ ) -> tuple[bool, str]:
358
385
  """Send audio message via API."""
359
386
  if not media_path.endswith(".ogg"):
360
387
  try:
361
388
  media_path = audio.convert_to_opus_ogg_temp(media_path)
362
389
  except Exception as e:
363
- return False, f"Error converting file to opus ogg. You likely need to install ffmpeg: {str(e)}"
364
-
365
- payload = {
366
- "user_id": user_id,
367
- "recipient": recipient,
368
- "media_path": media_path
369
- }
370
-
390
+ return (
391
+ False,
392
+ f"Error converting file to opus ogg. You likely need to install ffmpeg: {str(e)}",
393
+ )
394
+
395
+ payload = {"user_id": user_id, "recipient": recipient, "media_path": media_path}
396
+
371
397
  result = _make_api_request("send", method="POST", data=payload, user_id=user_id)
372
-
398
+
373
399
  if "error" in result:
374
400
  return False, result["error"]
375
-
401
+
376
402
  return result.get("success", False), result.get("message", "Unknown response")
377
403
 
378
- def download_media(message_id: str, chat_jid: str, user_id: str = "default_user") -> Optional[str]:
404
+
405
+ def download_media(
406
+ message_id: str, chat_jid: str, user_id: str = "default_user"
407
+ ) -> str | None:
379
408
  """Download media from a message via API."""
380
- payload = {
381
- "user_id": user_id,
382
- "message_id": message_id,
383
- "chat_jid": chat_jid
384
- }
385
-
409
+ payload = {"user_id": user_id, "message_id": message_id, "chat_jid": chat_jid}
410
+
386
411
  result = _make_api_request("download", method="POST", data=payload, user_id=user_id)
387
-
412
+
388
413
  if "error" in result:
389
- print(f"Download failed: {result['error']}")
390
414
  return None
391
-
415
+
392
416
  if result.get("success", False):
393
417
  path = result.get("path")
394
- print(f"Media downloaded successfully: {path}")
395
418
  return path
396
419
  else:
397
- print(f"Download failed: {result.get('message', 'Unknown error')}")
398
420
  return None